From 8f9dbf9e13b927de2524116c30544f7dfbbbf56c Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Wed, 13 Jul 2011 17:39:11 -0700 Subject: [PATCH] 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 --- include/gui/SurfaceTextureClient.h | 74 ++++--- include/surfaceflinger/Surface.h | 69 +------ libs/gui/Surface.cpp | 288 +++------------------------- libs/gui/SurfaceTexture.cpp | 8 +- libs/gui/SurfaceTextureClient.cpp | 257 +++++++++++++++++++++---- libs/ui/FramebufferNativeWindow.cpp | 4 + 6 files changed, 308 insertions(+), 392 deletions(-) diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h index 5ec469e9b..cfe2aa13b 100644 --- a/include/gui/SurfaceTextureClient.h +++ b/include/gui/SurfaceTextureClient.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -37,29 +38,24 @@ public: sp getISurfaceTexture() const; -private: - friend class Surface; +protected: + SurfaceTextureClient(); + void setISurfaceTexture(const sp& 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 mLockedBuffer; + sp mPostedBuffer; + mutable Region mOldDirtyRegion; + bool mConnectedToCpu; }; }; // namespace android diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h index dc2a84562..c2a494de4 100644 --- a/include/surfaceflinger/Surface.h +++ b/include/surfaceflinger/Surface.h @@ -28,6 +28,8 @@ #include #include +#include + #include #include @@ -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 +class Surface : public SurfaceTextureClient { public: struct SurfaceInfo { @@ -158,32 +154,14 @@ public: sp 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 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& 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 mSurface; - sp 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 mLockedBuffer; - sp 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 > sCachedSurfaces; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 9185e1e99..dabe643f2 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -46,59 +46,6 @@ namespace android { -// ---------------------------------------------------------------------- - -static status_t copyBlt( - const sp& dst, - const sp& 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 SurfaceControl::getSurface() const // --------------------------------------------------------------------------- Surface::Surface(const sp& 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& surface) } Surface::Surface(const Parcel& parcel, const sp& ref) - : mInitCheck(NO_INIT) + : SurfaceTextureClient(), + mInitCheck(NO_INIT) { mSurface = interface_cast(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 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(ANativeWindow::xdpi) = dinfo.xdpi; const_cast(ANativeWindow::ydpi) = dinfo.ydpi; - - const_cast(ANativeWindow::minSwapInterval) = - mSurfaceTextureClient->minSwapInterval; - - const_cast(ANativeWindow::maxSwapInterval) = - mSurfaceTextureClient->maxSwapInterval; - const_cast(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 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 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& 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(); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 14104810f..a12d40adc 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -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; diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp index f39cabf09..d5b7c89f8 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -24,24 +24,45 @@ namespace android { SurfaceTextureClient::SurfaceTextureClient( - const sp& 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& 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(ANativeWindow::minSwapInterval) = 0; const_cast(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& surfaceTexture) +{ + mSurfaceTexture = surfaceTexture; + // Get a reference to the allocator. mAllocator = mSurfaceTexture->getAllocator(); } @@ -50,42 +71,42 @@ sp 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& dst, + const sp& 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 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(*inOutDirtyBounds)); + newDirtyRegion.andSelf(bounds); + } else { + newDirtyRegion.set(bounds); + } + + // figure out if we can copy the frontbuffer back + const sp& 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 diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp index 9c10c754b..794747d65 100644 --- a/libs/ui/FramebufferNativeWindow.cpp +++ b/libs/ui/FramebufferNativeWindow.cpp @@ -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; }