move lock/unlock implementaion outside of Surface into SurfaceTextureClient
This makes ANativeWindow_lock/ANativeWindow_unlockAndPost work with ANativeWindows implemented by Surface and SurfaceTextureClient. Also, Surface now inherits directly from SurfaceTextureClient. Bug: 5003724 Change-Id: I9f285877c7bae9a262e9a7af91c2bae78804b2ef
This commit is contained in:
parent
9c8b60dad3
commit
8f9dbf9e13
|
@ -21,6 +21,7 @@
|
|||
#include <gui/SurfaceTexture.h>
|
||||
|
||||
#include <ui/egl/android_natives.h>
|
||||
#include <ui/Region.h>
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/threads.h>
|
||||
|
@ -37,29 +38,24 @@ public:
|
|||
|
||||
sp<ISurfaceTexture> getISurfaceTexture() const;
|
||||
|
||||
private:
|
||||
friend class Surface;
|
||||
protected:
|
||||
SurfaceTextureClient();
|
||||
void setISurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture);
|
||||
|
||||
private:
|
||||
// can't be copied
|
||||
SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
|
||||
SurfaceTextureClient(const SurfaceTextureClient& rhs);
|
||||
void init();
|
||||
|
||||
// ANativeWindow hooks
|
||||
static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
|
||||
static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
|
||||
static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
|
||||
static int perform(ANativeWindow* window, int operation, ...);
|
||||
static int query(const ANativeWindow* window, int what, int* value);
|
||||
static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
|
||||
static int setSwapInterval(ANativeWindow* window, int interval);
|
||||
|
||||
int cancelBuffer(ANativeWindowBuffer* buffer);
|
||||
int dequeueBuffer(ANativeWindowBuffer** buffer);
|
||||
int lockBuffer(ANativeWindowBuffer* buffer);
|
||||
int perform(int operation, va_list args);
|
||||
int query(int what, int* value) const;
|
||||
int queueBuffer(ANativeWindowBuffer* buffer);
|
||||
int setSwapInterval(int interval);
|
||||
static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
|
||||
static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
|
||||
static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
|
||||
static int hook_perform(ANativeWindow* window, int operation, ...);
|
||||
static int hook_query(const ANativeWindow* window, int what, int* value);
|
||||
static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
|
||||
static int hook_setSwapInterval(ANativeWindow* window, int interval);
|
||||
|
||||
int dispatchConnect(va_list args);
|
||||
int dispatchDisconnect(va_list args);
|
||||
|
@ -71,26 +67,38 @@ private:
|
|||
int dispatchSetBuffersTimestamp(va_list args);
|
||||
int dispatchSetCrop(va_list args);
|
||||
int dispatchSetUsage(va_list args);
|
||||
int dispatchLock(va_list args);
|
||||
int dispatchUnlockAndPost(va_list args);
|
||||
|
||||
int connect(int api);
|
||||
int disconnect(int api);
|
||||
int setBufferCount(int bufferCount);
|
||||
int setBuffersDimensions(int w, int h);
|
||||
int setBuffersFormat(int format);
|
||||
int setBuffersTransform(int transform);
|
||||
int setBuffersTimestamp(int64_t timestamp);
|
||||
int setCrop(Rect const* rect);
|
||||
int setUsage(uint32_t reqUsage);
|
||||
protected:
|
||||
virtual int cancelBuffer(ANativeWindowBuffer* buffer);
|
||||
virtual int dequeueBuffer(ANativeWindowBuffer** buffer);
|
||||
virtual int lockBuffer(ANativeWindowBuffer* buffer);
|
||||
virtual int perform(int operation, va_list args);
|
||||
virtual int query(int what, int* value) const;
|
||||
virtual int queueBuffer(ANativeWindowBuffer* buffer);
|
||||
virtual int setSwapInterval(int interval);
|
||||
|
||||
void freeAllBuffers();
|
||||
int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
|
||||
|
||||
int getConnectedApi() const;
|
||||
virtual int connect(int api);
|
||||
virtual int disconnect(int api);
|
||||
virtual int setBufferCount(int bufferCount);
|
||||
virtual int setBuffersDimensions(int w, int h);
|
||||
virtual int setBuffersFormat(int format);
|
||||
virtual int setBuffersTransform(int transform);
|
||||
virtual int setBuffersTimestamp(int64_t timestamp);
|
||||
virtual int setCrop(Rect const* rect);
|
||||
virtual int setUsage(uint32_t reqUsage);
|
||||
virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
|
||||
virtual int unlockAndPost();
|
||||
|
||||
enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
|
||||
enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
|
||||
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
|
||||
|
||||
private:
|
||||
void freeAllBuffers();
|
||||
int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
|
||||
|
||||
// mSurfaceTexture is the interface to the surface texture server. All
|
||||
// operations on the surface texture client ultimately translate into
|
||||
// interactions with the server using this interface.
|
||||
|
@ -145,6 +153,12 @@ private:
|
|||
// variables of SurfaceTexture objects. It must be locked whenever the
|
||||
// member variables are accessed.
|
||||
mutable Mutex mMutex;
|
||||
|
||||
// must be used from the lock/unlock thread
|
||||
sp<GraphicBuffer> mLockedBuffer;
|
||||
sp<GraphicBuffer> mPostedBuffer;
|
||||
mutable Region mOldDirtyRegion;
|
||||
bool mConnectedToCpu;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <ui/Region.h>
|
||||
#include <ui/egl/android_natives.h>
|
||||
|
||||
#include <gui/SurfaceTextureClient.h>
|
||||
|
||||
#include <surfaceflinger/ISurface.h>
|
||||
#include <surfaceflinger/ISurfaceComposerClient.h>
|
||||
|
||||
|
@ -37,14 +39,9 @@ namespace android {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class GraphicBuffer;
|
||||
class GraphicBufferMapper;
|
||||
class IOMX;
|
||||
class ISurfaceTexture;
|
||||
class Rect;
|
||||
class Surface;
|
||||
class SurfaceComposerClient;
|
||||
class SurfaceTextureClient;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
@ -129,8 +126,7 @@ private:
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class Surface
|
||||
: public EGLNativeBase<ANativeWindow, Surface, RefBase>
|
||||
class Surface : public SurfaceTextureClient
|
||||
{
|
||||
public:
|
||||
struct SurfaceInfo {
|
||||
|
@ -158,32 +154,14 @@ public:
|
|||
sp<ISurfaceTexture> getSurfaceTexture();
|
||||
|
||||
// the lock/unlock APIs must be used from the same thread
|
||||
status_t lock(SurfaceInfo* info, bool blocking = true);
|
||||
status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
|
||||
status_t lock(SurfaceInfo* info, Region* dirty = NULL);
|
||||
status_t unlockAndPost();
|
||||
|
||||
sp<IBinder> asBinder() const;
|
||||
|
||||
private:
|
||||
/*
|
||||
* Android frameworks friends
|
||||
* (eventually this should go away and be replaced by proper APIs)
|
||||
*/
|
||||
// camera and camcorder need access to the ISurface binder interface for preview
|
||||
friend class CameraService;
|
||||
friend class MediaRecorder;
|
||||
// MediaPlayer needs access to ISurface for display
|
||||
friend class MediaPlayer;
|
||||
friend class IOMX;
|
||||
friend class SoftwareRenderer;
|
||||
// this is just to be able to write some unit tests
|
||||
friend class Test;
|
||||
// videoEditor preview classes
|
||||
friend class VideoEditorPreviewController;
|
||||
friend class PreviewRenderer;
|
||||
|
||||
private:
|
||||
friend class SurfaceComposerClient;
|
||||
friend class SurfaceControl;
|
||||
|
||||
// can't be copied
|
||||
|
@ -194,62 +172,27 @@ private:
|
|||
Surface(const Parcel& data, const sp<IBinder>& ref);
|
||||
~Surface();
|
||||
|
||||
|
||||
/*
|
||||
* ANativeWindow hooks
|
||||
*/
|
||||
static int setSwapInterval(ANativeWindow* window, int interval);
|
||||
static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
|
||||
static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
|
||||
static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
|
||||
static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
|
||||
static int query(const ANativeWindow* window, int what, int* value);
|
||||
static int perform(ANativeWindow* window, int operation, ...);
|
||||
|
||||
int setSwapInterval(int interval);
|
||||
int dequeueBuffer(ANativeWindowBuffer** buffer);
|
||||
int lockBuffer(ANativeWindowBuffer* buffer);
|
||||
int queueBuffer(ANativeWindowBuffer* buffer);
|
||||
int cancelBuffer(ANativeWindowBuffer* buffer);
|
||||
int query(int what, int* value) const;
|
||||
int perform(int operation, va_list args);
|
||||
|
||||
/*
|
||||
* private stuff...
|
||||
*/
|
||||
void init();
|
||||
status_t validate(bool inCancelBuffer = false) const;
|
||||
|
||||
int getConnectedApi() const;
|
||||
|
||||
static void cleanCachedSurfacesLocked();
|
||||
|
||||
virtual int query(int what, int* value) const;
|
||||
|
||||
// constants
|
||||
status_t mInitCheck;
|
||||
sp<ISurface> mSurface;
|
||||
sp<SurfaceTextureClient> mSurfaceTextureClient;
|
||||
uint32_t mIdentity;
|
||||
PixelFormat mFormat;
|
||||
uint32_t mFlags;
|
||||
|
||||
// protected by mSurfaceLock. These are also used from lock/unlock
|
||||
// but in that case, they must be called form the same thread.
|
||||
mutable Region mDirtyRegion;
|
||||
|
||||
// must be used from the lock/unlock thread
|
||||
sp<GraphicBuffer> mLockedBuffer;
|
||||
sp<GraphicBuffer> mPostedBuffer;
|
||||
mutable Region mOldDirtyRegion;
|
||||
bool mReserved;
|
||||
|
||||
// query() must be called from dequeueBuffer() thread
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
|
||||
// Inherently thread-safe
|
||||
mutable Mutex mSurfaceLock;
|
||||
mutable Mutex mApiLock;
|
||||
|
||||
// A cache of Surface objects that have been deserialized into this process.
|
||||
static Mutex sCachedSurfacesLock;
|
||||
static DefaultKeyedVector<wp<IBinder>, wp<Surface> > sCachedSurfaces;
|
||||
|
|
|
@ -46,59 +46,6 @@
|
|||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
static status_t copyBlt(
|
||||
const sp<GraphicBuffer>& dst,
|
||||
const sp<GraphicBuffer>& src,
|
||||
const Region& reg)
|
||||
{
|
||||
// src and dst with, height and format must be identical. no verification
|
||||
// is done here.
|
||||
status_t err;
|
||||
uint8_t const * src_bits = NULL;
|
||||
err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
|
||||
LOGE_IF(err, "error locking src buffer %s", strerror(-err));
|
||||
|
||||
uint8_t* dst_bits = NULL;
|
||||
err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
|
||||
LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
|
||||
|
||||
Region::const_iterator head(reg.begin());
|
||||
Region::const_iterator tail(reg.end());
|
||||
if (head != tail && src_bits && dst_bits) {
|
||||
const size_t bpp = bytesPerPixel(src->format);
|
||||
const size_t dbpr = dst->stride * bpp;
|
||||
const size_t sbpr = src->stride * bpp;
|
||||
|
||||
while (head != tail) {
|
||||
const Rect& r(*head++);
|
||||
ssize_t h = r.height();
|
||||
if (h <= 0) continue;
|
||||
size_t size = r.width() * bpp;
|
||||
uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
|
||||
uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
|
||||
if (dbpr==sbpr && size==sbpr) {
|
||||
size *= h;
|
||||
h = 1;
|
||||
}
|
||||
do {
|
||||
memcpy(d, s, size);
|
||||
d += dbpr;
|
||||
s += sbpr;
|
||||
} while (--h > 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (src_bits)
|
||||
src->unlock();
|
||||
|
||||
if (dst_bits)
|
||||
dst->unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// SurfaceControl
|
||||
// ============================================================================
|
||||
|
@ -277,7 +224,8 @@ sp<Surface> SurfaceControl::getSurface() const
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
Surface::Surface(const sp<SurfaceControl>& surface)
|
||||
: mInitCheck(NO_INIT),
|
||||
: SurfaceTextureClient(),
|
||||
mInitCheck(NO_INIT),
|
||||
mSurface(surface->mSurface),
|
||||
mIdentity(surface->mIdentity),
|
||||
mFormat(surface->mFormat), mFlags(surface->mFlags),
|
||||
|
@ -287,7 +235,8 @@ Surface::Surface(const sp<SurfaceControl>& surface)
|
|||
}
|
||||
|
||||
Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
|
||||
: mInitCheck(NO_INIT)
|
||||
: SurfaceTextureClient(),
|
||||
mInitCheck(NO_INIT)
|
||||
{
|
||||
mSurface = interface_cast<ISurface>(ref);
|
||||
mIdentity = parcel.readInt32();
|
||||
|
@ -363,36 +312,21 @@ void Surface::cleanCachedSurfacesLocked() {
|
|||
|
||||
void Surface::init()
|
||||
{
|
||||
ANativeWindow::setSwapInterval = setSwapInterval;
|
||||
ANativeWindow::dequeueBuffer = dequeueBuffer;
|
||||
ANativeWindow::cancelBuffer = cancelBuffer;
|
||||
ANativeWindow::lockBuffer = lockBuffer;
|
||||
ANativeWindow::queueBuffer = queueBuffer;
|
||||
ANativeWindow::query = query;
|
||||
ANativeWindow::perform = perform;
|
||||
|
||||
if (mSurface != NULL) {
|
||||
sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture());
|
||||
LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
|
||||
if (surfaceTexture != NULL) {
|
||||
mSurfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
|
||||
mSurfaceTextureClient->setUsage(GraphicBuffer::USAGE_HW_RENDER);
|
||||
setISurfaceTexture(surfaceTexture);
|
||||
setUsage(GraphicBuffer::USAGE_HW_RENDER);
|
||||
}
|
||||
|
||||
DisplayInfo dinfo;
|
||||
SurfaceComposerClient::getDisplayInfo(0, &dinfo);
|
||||
const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
|
||||
const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
|
||||
|
||||
const_cast<int&>(ANativeWindow::minSwapInterval) =
|
||||
mSurfaceTextureClient->minSwapInterval;
|
||||
|
||||
const_cast<int&>(ANativeWindow::maxSwapInterval) =
|
||||
mSurfaceTextureClient->maxSwapInterval;
|
||||
|
||||
const_cast<uint32_t&>(ANativeWindow::flags) = 0;
|
||||
|
||||
if (mSurfaceTextureClient != 0) {
|
||||
if (surfaceTexture != NULL) {
|
||||
mInitCheck = NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -402,7 +336,6 @@ Surface::~Surface()
|
|||
{
|
||||
// clear all references and trigger an IPC now, to make sure things
|
||||
// happen without delay, since these resources are quite heavy.
|
||||
mSurfaceTextureClient.clear();
|
||||
mSurface.clear();
|
||||
IPCThreadState::self()->flushCommands();
|
||||
}
|
||||
|
@ -431,77 +364,6 @@ sp<IBinder> Surface::asBinder() const {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int Surface::setSwapInterval(ANativeWindow* window, int interval) {
|
||||
Surface* self = getSelf(window);
|
||||
return self->setSwapInterval(interval);
|
||||
}
|
||||
|
||||
int Surface::dequeueBuffer(ANativeWindow* window,
|
||||
ANativeWindowBuffer** buffer) {
|
||||
Surface* self = getSelf(window);
|
||||
return self->dequeueBuffer(buffer);
|
||||
}
|
||||
|
||||
int Surface::cancelBuffer(ANativeWindow* window,
|
||||
ANativeWindowBuffer* buffer) {
|
||||
Surface* self = getSelf(window);
|
||||
return self->cancelBuffer(buffer);
|
||||
}
|
||||
|
||||
int Surface::lockBuffer(ANativeWindow* window,
|
||||
ANativeWindowBuffer* buffer) {
|
||||
Surface* self = getSelf(window);
|
||||
return self->lockBuffer(buffer);
|
||||
}
|
||||
|
||||
int Surface::queueBuffer(ANativeWindow* window,
|
||||
ANativeWindowBuffer* buffer) {
|
||||
Surface* self = getSelf(window);
|
||||
return self->queueBuffer(buffer);
|
||||
}
|
||||
|
||||
int Surface::query(const ANativeWindow* window,
|
||||
int what, int* value) {
|
||||
const Surface* self = getSelf(window);
|
||||
return self->query(what, value);
|
||||
}
|
||||
|
||||
int Surface::perform(ANativeWindow* window,
|
||||
int operation, ...) {
|
||||
va_list args;
|
||||
va_start(args, operation);
|
||||
Surface* self = getSelf(window);
|
||||
int res = self->perform(operation, args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int Surface::setSwapInterval(int interval) {
|
||||
return mSurfaceTextureClient->setSwapInterval(interval);
|
||||
}
|
||||
|
||||
int Surface::dequeueBuffer(ANativeWindowBuffer** buffer) {
|
||||
status_t err = mSurfaceTextureClient->dequeueBuffer(buffer);
|
||||
if (err == NO_ERROR) {
|
||||
mDirtyRegion.set(buffer[0]->width, buffer[0]->height);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int Surface::cancelBuffer(ANativeWindowBuffer* buffer) {
|
||||
return mSurfaceTextureClient->cancelBuffer(buffer);
|
||||
}
|
||||
|
||||
int Surface::lockBuffer(ANativeWindowBuffer* buffer) {
|
||||
return mSurfaceTextureClient->lockBuffer(buffer);
|
||||
}
|
||||
|
||||
int Surface::queueBuffer(ANativeWindowBuffer* buffer) {
|
||||
return mSurfaceTextureClient->queueBuffer(buffer);
|
||||
}
|
||||
|
||||
int Surface::query(int what, int* value) const {
|
||||
switch (what) {
|
||||
case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
|
||||
|
@ -509,141 +371,39 @@ int Surface::query(int what, int* value) const {
|
|||
*value = 1;
|
||||
return NO_ERROR;
|
||||
case NATIVE_WINDOW_CONCRETE_TYPE:
|
||||
// TODO: this is not needed anymore
|
||||
*value = NATIVE_WINDOW_SURFACE;
|
||||
return NO_ERROR;
|
||||
}
|
||||
return mSurfaceTextureClient->query(what, value);
|
||||
}
|
||||
|
||||
int Surface::perform(int operation, va_list args) {
|
||||
return mSurfaceTextureClient->perform(operation, args);
|
||||
return SurfaceTextureClient::query(what, value);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int Surface::getConnectedApi() const {
|
||||
return mSurfaceTextureClient->getConnectedApi();
|
||||
}
|
||||
status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn) {
|
||||
ANativeWindow_Buffer outBuffer;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
status_t Surface::lock(SurfaceInfo* info, bool blocking) {
|
||||
return Surface::lock(info, NULL, blocking);
|
||||
}
|
||||
|
||||
status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
|
||||
{
|
||||
if (getConnectedApi()) {
|
||||
LOGE("Surface::lock(%p) failed. Already connected to another API",
|
||||
(ANativeWindow*)this);
|
||||
CallStack stack;
|
||||
stack.update();
|
||||
stack.dump("");
|
||||
return INVALID_OPERATION;
|
||||
ARect temp;
|
||||
ARect* inOutDirtyBounds = NULL;
|
||||
if (dirtyIn) {
|
||||
temp = dirtyIn->getBounds();
|
||||
inOutDirtyBounds = &temp;
|
||||
}
|
||||
|
||||
if (mApiLock.tryLock() != NO_ERROR) {
|
||||
LOGE("calling Surface::lock from different threads!");
|
||||
CallStack stack;
|
||||
stack.update();
|
||||
stack.dump("");
|
||||
return WOULD_BLOCK;
|
||||
}
|
||||
status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds);
|
||||
|
||||
/* Here we're holding mApiLock */
|
||||
|
||||
if (mLockedBuffer != 0) {
|
||||
LOGE("Surface::lock failed, already locked");
|
||||
mApiLock.unlock();
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
// we're intending to do software rendering from this point
|
||||
mSurfaceTextureClient->setUsage(
|
||||
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
|
||||
|
||||
ANativeWindowBuffer* out;
|
||||
status_t err = mSurfaceTextureClient->dequeueBuffer(&out);
|
||||
LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
|
||||
if (err == NO_ERROR) {
|
||||
sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
|
||||
err = mSurfaceTextureClient->lockBuffer(backBuffer.get());
|
||||
LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
|
||||
backBuffer->handle, strerror(-err));
|
||||
if (err == NO_ERROR) {
|
||||
const Rect bounds(backBuffer->width, backBuffer->height);
|
||||
const Region boundsRegion(bounds);
|
||||
Region scratch(boundsRegion);
|
||||
Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
|
||||
newDirtyRegion &= boundsRegion;
|
||||
|
||||
// figure out if we can copy the frontbuffer back
|
||||
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
|
||||
const bool canCopyBack = (frontBuffer != 0 &&
|
||||
backBuffer->width == frontBuffer->width &&
|
||||
backBuffer->height == frontBuffer->height &&
|
||||
backBuffer->format == frontBuffer->format &&
|
||||
!(mFlags & ISurfaceComposer::eDestroyBackbuffer));
|
||||
|
||||
// the dirty region we report to surfaceflinger is the one
|
||||
// given by the user (as opposed to the one *we* return to the
|
||||
// user).
|
||||
mDirtyRegion = newDirtyRegion;
|
||||
|
||||
if (canCopyBack) {
|
||||
// copy the area that is invalid and not repainted this round
|
||||
const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
|
||||
if (!copyback.isEmpty())
|
||||
copyBlt(backBuffer, frontBuffer, copyback);
|
||||
} else {
|
||||
// if we can't copy-back anything, modify the user's dirty
|
||||
// region to make sure they redraw the whole buffer
|
||||
newDirtyRegion = boundsRegion;
|
||||
}
|
||||
|
||||
// keep track of the are of the buffer that is "clean"
|
||||
// (ie: that will be redrawn)
|
||||
mOldDirtyRegion = newDirtyRegion;
|
||||
|
||||
void* vaddr;
|
||||
status_t res = backBuffer->lock(
|
||||
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
|
||||
newDirtyRegion.bounds(), &vaddr);
|
||||
|
||||
LOGW_IF(res, "failed locking buffer (handle = %p)",
|
||||
backBuffer->handle);
|
||||
|
||||
mLockedBuffer = backBuffer;
|
||||
other->w = backBuffer->width;
|
||||
other->h = backBuffer->height;
|
||||
other->s = backBuffer->stride;
|
||||
other->usage = backBuffer->usage;
|
||||
other->format = backBuffer->format;
|
||||
other->bits = vaddr;
|
||||
}
|
||||
other->w = uint32_t(outBuffer.width);
|
||||
other->h = uint32_t(outBuffer.height);
|
||||
other->s = uint32_t(outBuffer.stride);
|
||||
other->usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
|
||||
other->format = uint32_t(outBuffer.format);
|
||||
other->bits = outBuffer.bits;
|
||||
}
|
||||
mApiLock.unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t Surface::unlockAndPost()
|
||||
{
|
||||
if (mLockedBuffer == 0) {
|
||||
LOGE("Surface::unlockAndPost failed, no locked buffer");
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
status_t err = mLockedBuffer->unlock();
|
||||
LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
|
||||
|
||||
err = mSurfaceTextureClient->queueBuffer(mLockedBuffer.get());
|
||||
LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
|
||||
mLockedBuffer->handle, strerror(-err));
|
||||
|
||||
mPostedBuffer = mLockedBuffer;
|
||||
mLockedBuffer = 0;
|
||||
return err;
|
||||
status_t Surface::unlockAndPost() {
|
||||
return SurfaceTextureClient::unlockAndPost();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -495,7 +495,7 @@ status_t SurfaceTexture::setTransform(uint32_t transform) {
|
|||
}
|
||||
|
||||
status_t SurfaceTexture::connect(int api) {
|
||||
LOGV("SurfaceTexture::connect");
|
||||
LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
|
||||
Mutex::Autolock lock(mMutex);
|
||||
int err = NO_ERROR;
|
||||
switch (api) {
|
||||
|
@ -504,6 +504,8 @@ status_t SurfaceTexture::connect(int api) {
|
|||
case NATIVE_WINDOW_API_MEDIA:
|
||||
case NATIVE_WINDOW_API_CAMERA:
|
||||
if (mConnectedApi != NO_CONNECTED_API) {
|
||||
LOGE("connect: already connected (cur=%d, req=%d)",
|
||||
mConnectedApi, api);
|
||||
err = -EINVAL;
|
||||
} else {
|
||||
mConnectedApi = api;
|
||||
|
@ -517,7 +519,7 @@ status_t SurfaceTexture::connect(int api) {
|
|||
}
|
||||
|
||||
status_t SurfaceTexture::disconnect(int api) {
|
||||
LOGV("SurfaceTexture::disconnect");
|
||||
LOGV("SurfaceTexture::disconnect(this=%p, %d)", this, api);
|
||||
Mutex::Autolock lock(mMutex);
|
||||
int err = NO_ERROR;
|
||||
switch (api) {
|
||||
|
@ -528,6 +530,8 @@ status_t SurfaceTexture::disconnect(int api) {
|
|||
if (mConnectedApi == api) {
|
||||
mConnectedApi = NO_CONNECTED_API;
|
||||
} else {
|
||||
LOGE("disconnect: connected to another api (cur=%d, req=%d)",
|
||||
mConnectedApi, api);
|
||||
err = -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -24,24 +24,45 @@
|
|||
namespace android {
|
||||
|
||||
SurfaceTextureClient::SurfaceTextureClient(
|
||||
const sp<ISurfaceTexture>& surfaceTexture):
|
||||
mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
|
||||
mReqHeight(0), mReqFormat(0), mReqUsage(0),
|
||||
mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO),
|
||||
mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
|
||||
mMutex() {
|
||||
const sp<ISurfaceTexture>& surfaceTexture)
|
||||
{
|
||||
SurfaceTextureClient::init();
|
||||
SurfaceTextureClient::setISurfaceTexture(surfaceTexture);
|
||||
}
|
||||
|
||||
SurfaceTextureClient::SurfaceTextureClient() {
|
||||
SurfaceTextureClient::init();
|
||||
}
|
||||
|
||||
void SurfaceTextureClient::init() {
|
||||
// Initialize the ANativeWindow function pointers.
|
||||
ANativeWindow::setSwapInterval = setSwapInterval;
|
||||
ANativeWindow::dequeueBuffer = dequeueBuffer;
|
||||
ANativeWindow::cancelBuffer = cancelBuffer;
|
||||
ANativeWindow::lockBuffer = lockBuffer;
|
||||
ANativeWindow::queueBuffer = queueBuffer;
|
||||
ANativeWindow::query = query;
|
||||
ANativeWindow::perform = perform;
|
||||
ANativeWindow::setSwapInterval = hook_setSwapInterval;
|
||||
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
|
||||
ANativeWindow::cancelBuffer = hook_cancelBuffer;
|
||||
ANativeWindow::lockBuffer = hook_lockBuffer;
|
||||
ANativeWindow::queueBuffer = hook_queueBuffer;
|
||||
ANativeWindow::query = hook_query;
|
||||
ANativeWindow::perform = hook_perform;
|
||||
|
||||
const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
|
||||
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
|
||||
|
||||
mReqWidth = 0;
|
||||
mReqHeight = 0;
|
||||
mReqFormat = 0;
|
||||
mReqUsage = 0;
|
||||
mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
|
||||
mQueryWidth = 0;
|
||||
mQueryHeight = 0;
|
||||
mQueryFormat = 0;
|
||||
mConnectedToCpu = false;
|
||||
}
|
||||
|
||||
void SurfaceTextureClient::setISurfaceTexture(
|
||||
const sp<ISurfaceTexture>& surfaceTexture)
|
||||
{
|
||||
mSurfaceTexture = surfaceTexture;
|
||||
|
||||
// Get a reference to the allocator.
|
||||
mAllocator = mSurfaceTexture->getAllocator();
|
||||
}
|
||||
|
@ -50,42 +71,42 @@ sp<ISurfaceTexture> SurfaceTextureClient::getISurfaceTexture() const {
|
|||
return mSurfaceTexture;
|
||||
}
|
||||
|
||||
int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) {
|
||||
int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interval) {
|
||||
SurfaceTextureClient* c = getSelf(window);
|
||||
return c->setSwapInterval(interval);
|
||||
}
|
||||
|
||||
int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
|
||||
int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window,
|
||||
ANativeWindowBuffer** buffer) {
|
||||
SurfaceTextureClient* c = getSelf(window);
|
||||
return c->dequeueBuffer(buffer);
|
||||
}
|
||||
|
||||
int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
|
||||
int SurfaceTextureClient::hook_cancelBuffer(ANativeWindow* window,
|
||||
ANativeWindowBuffer* buffer) {
|
||||
SurfaceTextureClient* c = getSelf(window);
|
||||
return c->cancelBuffer(buffer);
|
||||
}
|
||||
|
||||
int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
|
||||
int SurfaceTextureClient::hook_lockBuffer(ANativeWindow* window,
|
||||
ANativeWindowBuffer* buffer) {
|
||||
SurfaceTextureClient* c = getSelf(window);
|
||||
return c->lockBuffer(buffer);
|
||||
}
|
||||
|
||||
int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
|
||||
int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window,
|
||||
ANativeWindowBuffer* buffer) {
|
||||
SurfaceTextureClient* c = getSelf(window);
|
||||
return c->queueBuffer(buffer);
|
||||
}
|
||||
|
||||
int SurfaceTextureClient::query(const ANativeWindow* window,
|
||||
int SurfaceTextureClient::hook_query(const ANativeWindow* window,
|
||||
int what, int* value) {
|
||||
const SurfaceTextureClient* c = getSelf(window);
|
||||
return c->query(what, value);
|
||||
}
|
||||
|
||||
int SurfaceTextureClient::perform(ANativeWindow* window, int operation, ...) {
|
||||
int SurfaceTextureClient::hook_perform(ANativeWindow* window, int operation, ...) {
|
||||
va_list args;
|
||||
va_start(args, operation);
|
||||
SurfaceTextureClient* c = getSelf(window);
|
||||
|
@ -219,7 +240,6 @@ int SurfaceTextureClient::query(int what, int* value) const {
|
|||
*value = 0;
|
||||
return NO_ERROR;
|
||||
case NATIVE_WINDOW_CONCRETE_TYPE:
|
||||
// TODO: this is not needed anymore
|
||||
*value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
@ -260,6 +280,12 @@ int SurfaceTextureClient::perform(int operation, va_list args)
|
|||
case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
|
||||
res = dispatchSetBuffersFormat(args);
|
||||
break;
|
||||
case NATIVE_WINDOW_LOCK:
|
||||
res = dispatchLock(args);
|
||||
break;
|
||||
case NATIVE_WINDOW_UNLOCK_AND_POST:
|
||||
res = dispatchUnlockAndPost(args);
|
||||
break;
|
||||
default:
|
||||
res = NAME_NOT_FOUND;
|
||||
break;
|
||||
|
@ -324,28 +350,37 @@ int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) {
|
|||
return setBuffersTimestamp(timestamp);
|
||||
}
|
||||
|
||||
int SurfaceTextureClient::dispatchLock(va_list args) {
|
||||
ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
|
||||
ARect* inOutDirtyBounds = va_arg(args, ARect*);
|
||||
return lock(outBuffer, inOutDirtyBounds);
|
||||
}
|
||||
|
||||
int SurfaceTextureClient::dispatchUnlockAndPost(va_list args) {
|
||||
return unlockAndPost();
|
||||
}
|
||||
|
||||
|
||||
int SurfaceTextureClient::connect(int api) {
|
||||
LOGV("SurfaceTextureClient::connect");
|
||||
Mutex::Autolock lock(mMutex);
|
||||
return mSurfaceTexture->connect(api);
|
||||
int err = mSurfaceTexture->connect(api);
|
||||
if (!err && api == NATIVE_WINDOW_API_CPU) {
|
||||
mConnectedToCpu = true;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int SurfaceTextureClient::disconnect(int api) {
|
||||
LOGV("SurfaceTextureClient::disconnect");
|
||||
Mutex::Autolock lock(mMutex);
|
||||
return mSurfaceTexture->disconnect(api);
|
||||
int err = mSurfaceTexture->disconnect(api);
|
||||
if (!err && api == NATIVE_WINDOW_API_CPU) {
|
||||
mConnectedToCpu = false;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int SurfaceTextureClient::getConnectedApi() const
|
||||
{
|
||||
// XXX: This method will be going away shortly, and is currently bogus. It
|
||||
// always returns "nothing is connected". It will go away once Surface gets
|
||||
// updated to actually connect as the 'CPU' API when locking a buffer.
|
||||
Mutex::Autolock lock(mMutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int SurfaceTextureClient::setUsage(uint32_t reqUsage)
|
||||
{
|
||||
LOGV("SurfaceTextureClient::setUsage");
|
||||
|
@ -443,4 +478,160 @@ void SurfaceTextureClient::freeAllBuffers() {
|
|||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// the lock/unlock APIs must be used from the same thread
|
||||
|
||||
static status_t copyBlt(
|
||||
const sp<GraphicBuffer>& dst,
|
||||
const sp<GraphicBuffer>& src,
|
||||
const Region& reg)
|
||||
{
|
||||
// src and dst with, height and format must be identical. no verification
|
||||
// is done here.
|
||||
status_t err;
|
||||
uint8_t const * src_bits = NULL;
|
||||
err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
|
||||
LOGE_IF(err, "error locking src buffer %s", strerror(-err));
|
||||
|
||||
uint8_t* dst_bits = NULL;
|
||||
err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
|
||||
LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
|
||||
|
||||
Region::const_iterator head(reg.begin());
|
||||
Region::const_iterator tail(reg.end());
|
||||
if (head != tail && src_bits && dst_bits) {
|
||||
const size_t bpp = bytesPerPixel(src->format);
|
||||
const size_t dbpr = dst->stride * bpp;
|
||||
const size_t sbpr = src->stride * bpp;
|
||||
|
||||
while (head != tail) {
|
||||
const Rect& r(*head++);
|
||||
ssize_t h = r.height();
|
||||
if (h <= 0) continue;
|
||||
size_t size = r.width() * bpp;
|
||||
uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
|
||||
uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
|
||||
if (dbpr==sbpr && size==sbpr) {
|
||||
size *= h;
|
||||
h = 1;
|
||||
}
|
||||
do {
|
||||
memcpy(d, s, size);
|
||||
d += dbpr;
|
||||
s += sbpr;
|
||||
} while (--h > 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (src_bits)
|
||||
src->unlock();
|
||||
|
||||
if (dst_bits)
|
||||
dst->unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
status_t SurfaceTextureClient::lock(
|
||||
ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
|
||||
{
|
||||
if (mLockedBuffer != 0) {
|
||||
LOGE("Surface::lock failed, already locked");
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if (!mConnectedToCpu) {
|
||||
int err = SurfaceTextureClient::connect(NATIVE_WINDOW_API_CPU);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
// we're intending to do software rendering from this point
|
||||
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
|
||||
}
|
||||
|
||||
ANativeWindowBuffer* out;
|
||||
status_t err = dequeueBuffer(&out);
|
||||
LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
|
||||
if (err == NO_ERROR) {
|
||||
sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
|
||||
err = lockBuffer(backBuffer.get());
|
||||
LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
|
||||
backBuffer->handle, strerror(-err));
|
||||
if (err == NO_ERROR) {
|
||||
const Rect bounds(backBuffer->width, backBuffer->height);
|
||||
|
||||
Region newDirtyRegion;
|
||||
if (inOutDirtyBounds) {
|
||||
newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
|
||||
newDirtyRegion.andSelf(bounds);
|
||||
} else {
|
||||
newDirtyRegion.set(bounds);
|
||||
}
|
||||
|
||||
// figure out if we can copy the frontbuffer back
|
||||
const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
|
||||
const bool canCopyBack = (frontBuffer != 0 &&
|
||||
backBuffer->width == frontBuffer->width &&
|
||||
backBuffer->height == frontBuffer->height &&
|
||||
backBuffer->format == frontBuffer->format);
|
||||
|
||||
if (canCopyBack) {
|
||||
// copy the area that is invalid and not repainted this round
|
||||
const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
|
||||
if (!copyback.isEmpty())
|
||||
copyBlt(backBuffer, frontBuffer, copyback);
|
||||
} else {
|
||||
// if we can't copy-back anything, modify the user's dirty
|
||||
// region to make sure they redraw the whole buffer
|
||||
newDirtyRegion.set(bounds);
|
||||
}
|
||||
|
||||
// keep track of the are of the buffer that is "clean"
|
||||
// (ie: that will be redrawn)
|
||||
mOldDirtyRegion = newDirtyRegion;
|
||||
|
||||
if (inOutDirtyBounds) {
|
||||
*inOutDirtyBounds = newDirtyRegion.getBounds();
|
||||
}
|
||||
|
||||
void* vaddr;
|
||||
status_t res = backBuffer->lock(
|
||||
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
|
||||
newDirtyRegion.bounds(), &vaddr);
|
||||
|
||||
LOGW_IF(res, "failed locking buffer (handle = %p)",
|
||||
backBuffer->handle);
|
||||
|
||||
mLockedBuffer = backBuffer;
|
||||
outBuffer->width = backBuffer->width;
|
||||
outBuffer->height = backBuffer->height;
|
||||
outBuffer->stride = backBuffer->stride;
|
||||
outBuffer->format = backBuffer->format;
|
||||
outBuffer->bits = vaddr;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
status_t SurfaceTextureClient::unlockAndPost()
|
||||
{
|
||||
if (mLockedBuffer == 0) {
|
||||
LOGE("Surface::unlockAndPost failed, no locked buffer");
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
status_t err = mLockedBuffer->unlock();
|
||||
LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
|
||||
|
||||
err = queueBuffer(mLockedBuffer.get());
|
||||
LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
|
||||
mLockedBuffer->handle, strerror(-err));
|
||||
|
||||
mPostedBuffer = mLockedBuffer;
|
||||
mLockedBuffer = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
|
|
@ -303,6 +303,10 @@ int FramebufferNativeWindow::perform(ANativeWindow* window,
|
|||
case NATIVE_WINDOW_CONNECT:
|
||||
case NATIVE_WINDOW_DISCONNECT:
|
||||
break;
|
||||
case NATIVE_WINDOW_LOCK:
|
||||
return INVALID_OPERATION;
|
||||
case NATIVE_WINDOW_UNLOCK_AND_POST:
|
||||
return INVALID_OPERATION;
|
||||
default:
|
||||
return NAME_NOT_FOUND;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue