diff options
author | Mathias Agopian <mathias@google.com> | 2011-07-13 17:39:11 -0700 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2011-07-15 17:47:08 -0700 |
commit | 949be32b671304d5281ac0abbf30dcf4ebaa9eaf (patch) | |
tree | f12cbc9997bd2270f1a7604ba4d78739688975c3 /libs | |
parent | 8d96f19692815aa14979c811a130b38eafc1bf65 (diff) | |
download | frameworks_base-949be32b671304d5281ac0abbf30dcf4ebaa9eaf.zip frameworks_base-949be32b671304d5281ac0abbf30dcf4ebaa9eaf.tar.gz frameworks_base-949be32b671304d5281ac0abbf30dcf4ebaa9eaf.tar.bz2 |
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
Diffstat (limited to 'libs')
-rw-r--r-- | libs/gui/Surface.cpp | 288 | ||||
-rw-r--r-- | libs/gui/SurfaceTexture.cpp | 8 | ||||
-rw-r--r-- | libs/gui/SurfaceTextureClient.cpp | 257 | ||||
-rw-r--r-- | libs/ui/FramebufferNativeWindow.cpp | 4 |
4 files changed, 258 insertions, 299 deletions
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 9185e1e..dabe643f 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -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; - } - - if (mApiLock.tryLock() != NO_ERROR) { - LOGE("calling Surface::lock from different threads!"); - CallStack stack; - stack.update(); - stack.dump(""); - return WOULD_BLOCK; + ARect temp; + ARect* inOutDirtyBounds = NULL; + if (dirtyIn) { + temp = dirtyIn->getBounds(); + inOutDirtyBounds = &temp; } - /* 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); + status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds); - 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(); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 1410481..a12d40a 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 f39cabf..d5b7c89 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -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 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 err = mSurfaceTexture->disconnect(api); + if (!err && api == NATIVE_WINDOW_API_CPU) { + mConnectedToCpu = false; + } + return err; } - 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 diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp index 9c10c75..794747d 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; } |