diff options
| -rw-r--r-- | include/gui/SurfaceTexture.h | 13 | ||||
| -rw-r--r-- | libs/gui/SurfaceTexture.cpp | 14 | ||||
| -rw-r--r-- | services/surfaceflinger/Layer.cpp | 191 | ||||
| -rw-r--r-- | services/surfaceflinger/LayerBase.cpp | 8 | ||||
| -rw-r--r-- | services/surfaceflinger/LayerBase.h | 3 |
5 files changed, 160 insertions, 69 deletions
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index f9cf0bedf6..2635e2f3aa 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -236,6 +236,19 @@ protected: static bool isExternalFormat(uint32_t format); private: + // this version of updateTexImage() takes a functor used to reject or not + // the newly acquired buffer. + // this API is TEMPORARY and intended to be used by SurfaceFlinger only, + // which is why class Layer is made a friend of SurfaceTexture below. + class BufferRejecter { + friend class SurfaceTexture; + virtual bool reject(const sp<GraphicBuffer>& buf, + const BufferQueue::BufferItem& item) = 0; + protected: + virtual ~BufferRejecter() { } + }; + friend class Layer; + status_t updateTexImage(BufferRejecter* rejecter); // createImage creates a new EGLImage from a GraphicBuffer. EGLImageKHR createImage(EGLDisplay dpy, diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 30c0d9bfb1..55be4bcf2d 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -176,6 +176,10 @@ status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) } status_t SurfaceTexture::updateTexImage() { + return SurfaceTexture::updateTexImage(NULL); +} + +status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) { ATRACE_CALL(); ST_LOGV("updateTexImage"); Mutex::Autolock lock(mMutex); @@ -228,6 +232,16 @@ status_t SurfaceTexture::updateTexImage() { mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer; } + // we call the rejecter here, in case the caller has a reason to + // not accept this buffer. this is used by SurfaceFlinger to + // reject buffers which have the wrong size + if (rejecter && rejecter->reject(mEGLSlots[buf].mGraphicBuffer, item)) { + mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence); + mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR; + glBindTexture(mTexTarget, mTexName); + return NO_ERROR; + } + // Update the GL texture object. We may have to do this even when // item.mGraphicBuffer == NULL, if we destroyed the EGLImage when // detaching from a context but the buffer has not been re-allocated. diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 6ec4f4991c..5e17d07a15 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -428,38 +428,51 @@ uint32_t Layer::doTransaction(uint32_t flags) const Layer::State& front(drawingState()); const Layer::State& temp(currentState()); - const bool sizeChanged = (front.requested.w != temp.requested.w) || - (front.requested.h != temp.requested.h); + const bool sizeChanged = (temp.requested.w != front.active.w) || + (temp.requested.h != front.active.h); if (sizeChanged) { // the size changed, we need to ask our client to request a new buffer ALOGD_IF(DEBUG_RESIZE, - "doTransaction: " - "geometry (layer=%p), size: current (%dx%d), drawing (%dx%d), " - "crop: current (%d,%d,%d,%d [%dx%d]), drawing (%d,%d,%d,%d [%dx%d]), " - "scalingMode=%d", - this, - int(temp.requested.w), int(temp.requested.h), - int(front.requested.w), int(front.requested.h), + "doTransaction: geometry (layer=%p), scalingMode=%d\n" + " current={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" + " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n" + " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" + " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n", + this, mCurrentScalingMode, + temp.active.w, temp.active.h, + temp.active.crop.left, + temp.active.crop.top, + temp.active.crop.right, + temp.active.crop.bottom, + temp.active.crop.getWidth(), + temp.active.crop.getHeight(), + temp.requested.w, temp.requested.h, temp.requested.crop.left, temp.requested.crop.top, temp.requested.crop.right, temp.requested.crop.bottom, temp.requested.crop.getWidth(), temp.requested.crop.getHeight(), + front.active.w, front.active.h, + front.active.crop.left, + front.active.crop.top, + front.active.crop.right, + front.active.crop.bottom, + front.active.crop.getWidth(), + front.active.crop.getHeight(), + front.requested.w, front.requested.h, front.requested.crop.left, front.requested.crop.top, front.requested.crop.right, front.requested.crop.bottom, front.requested.crop.getWidth(), - front.requested.crop.getHeight(), - mCurrentScalingMode); + front.requested.crop.getHeight()); if (!isFixedSize()) { // this will make sure LayerBase::doTransaction doesn't update // the drawing state's geometry - Layer::State& editDraw(mDrawingState); - editDraw.requested = temp.requested; + flags |= eDontUpdateGeometryState; } // record the new size, form this point on, when the client request @@ -514,7 +527,91 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) mFlinger->signalLayerUpdate(); } - if (mSurfaceTexture->updateTexImage() < NO_ERROR) { + struct Reject : public SurfaceTexture::BufferRejecter { + Layer::State& front; + Layer::State& current; + bool& recomputeVisibleRegions; + Reject(Layer::State& front, Layer::State& current, + bool& recomputeVisibleRegions) + : front(front), current(current), + recomputeVisibleRegions(recomputeVisibleRegions) { + } + + virtual bool reject(const sp<GraphicBuffer>& buf, + const BufferQueue::BufferItem& item) { + if (buf == NULL) { + return false; + } + + uint32_t bufWidth = buf->getWidth(); + uint32_t bufHeight = buf->getHeight(); + + // check that we received a buffer of the right size + // (Take the buffer's orientation into account) + if (item.mTransform & Transform::ROT_90) { + swap(bufWidth, bufHeight); + } + + + bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE; + if (front.active != front.requested) { + + if (isFixedSize || + (bufWidth == front.requested.w && + bufHeight == front.requested.h)) + { + // Here we pretend the transaction happened by updating the + // current and drawing states. Drawing state is only accessed + // in this thread, no need to have it locked + front.active = front.requested; + + // We also need to update the current state so that + // we don't end-up overwriting the drawing state with + // this stale current state during the next transaction + // + // NOTE: We don't need to hold the transaction lock here + // because State::active is only accessed from this thread. + current.active = front.active; + + // recompute visible region + recomputeVisibleRegions = true; + } + + ALOGD_IF(DEBUG_RESIZE, + "lockPageFlip: (layer=%p), buffer (%ux%u, tr=%02x), scalingMode=%d\n" + " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" + " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n", + this, bufWidth, bufHeight, item.mTransform, item.mScalingMode, + front.active.w, front.active.h, + front.active.crop.left, + front.active.crop.top, + front.active.crop.right, + front.active.crop.bottom, + front.active.crop.getWidth(), + front.active.crop.getHeight(), + front.requested.w, front.requested.h, + front.requested.crop.left, + front.requested.crop.top, + front.requested.crop.right, + front.requested.crop.bottom, + front.requested.crop.getWidth(), + front.requested.crop.getHeight()); + } + + if (!isFixedSize) { + if (front.active.w != bufWidth || + front.active.h != bufHeight) { + return true; + } + } + return false; + } + }; + + + Reject r(mDrawingState, currentState(), recomputeVisibleRegions); + + if (mSurfaceTexture->updateTexImage(&r) < NO_ERROR) { // something happened! recomputeVisibleRegions = true; return; @@ -522,14 +619,18 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) // update the active buffer mActiveBuffer = mSurfaceTexture->getCurrentBuffer(); - mFrameLatencyNeeded = true; - - if (oldActiveBuffer == NULL && mActiveBuffer != NULL) { - // the first time we receive a buffer, we need to trigger a - // geometry invalidation. - mFlinger->invalidateHwcGeometry(); + if (mActiveBuffer == NULL) { + // this can only happen if the very first buffer was rejected. + return; } + mFrameLatencyNeeded = true; + if (oldActiveBuffer == NULL) { + // the first time we receive a buffer, we need to trigger a + // geometry invalidation. + mFlinger->invalidateHwcGeometry(); + } + Rect crop(mSurfaceTexture->getCurrentCrop()); const uint32_t transform(mSurfaceTexture->getCurrentTransform()); const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode()); @@ -543,9 +644,9 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) mFlinger->invalidateHwcGeometry(); } - uint32_t bufWidth = mActiveBuffer->getWidth(); - uint32_t bufHeight = mActiveBuffer->getHeight(); if (oldActiveBuffer != NULL) { + uint32_t bufWidth = mActiveBuffer->getWidth(); + uint32_t bufHeight = mActiveBuffer->getHeight(); if (bufWidth != uint32_t(oldActiveBuffer->width) || bufHeight != uint32_t(oldActiveBuffer->height)) { mFlinger->invalidateHwcGeometry(); @@ -557,52 +658,12 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) recomputeVisibleRegions = true; } - glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - // update the layer size if needed - const Layer::State& front(drawingState()); - // FIXME: mPostedDirtyRegion = dirty & bounds + const Layer::State& front(drawingState()); mPostedDirtyRegion.set(front.active.w, front.active.h); - if (front.active != front.requested) { - // check that we received a buffer of the right size - // (Take the buffer's orientation into account) - if (mCurrentTransform & Transform::ROT_90) { - swap(bufWidth, bufHeight); - } - - if (isFixedSize() || - (bufWidth == front.requested.w && - bufHeight == front.requested.h)) - { - // Here we pretend the transaction happened by updating the - // current and drawing states. Drawing state is only accessed - // in this thread, no need to have it locked - Layer::State& editDraw(mDrawingState); - editDraw.active = editDraw.requested; - - // We also need to update the current state so that we don't - // end-up doing too much work during the next transaction. - // NOTE: We actually don't need hold the transaction lock here - // because State::w and State::h are only accessed from - // this thread - Layer::State& editTemp(currentState()); - editTemp.active = editDraw.active; - - // recompute visible region - recomputeVisibleRegions = true; - } - - ALOGD_IF(DEBUG_RESIZE, - "lockPageFlip : " - " (layer=%p), buffer (%ux%u, tr=%02x), " - "requested (%dx%d)", - this, - bufWidth, bufHeight, mCurrentTransform, - front.requested.w, front.requested.h); - } + glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } } diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index 7c6a28afb7..16bac8f79c 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -201,12 +201,14 @@ uint32_t LayerBase::doTransaction(uint32_t flags) const Layer::State& front(drawingState()); const Layer::State& temp(currentState()); - if (front.requested != temp.requested) { - // geometry of the layer has changed, set the active geometry - // to the requested geometry. + // always set active to requested, unless we're asked not to + // this is used by Layer, which special cases resizes. + if (flags & eDontUpdateGeometryState) { + } else { Layer::State& editTemp(currentState()); editTemp.active = temp.requested; } + if (front.active != temp.active) { // invalidate and recompute the visible regions if needed flags |= Layer::eVisibleRegion; diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index 9542424427..c547a40725 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -227,7 +227,8 @@ public: enum { // flags for doTransaction() - eVisibleRegion = 0x00000002, + eDontUpdateGeometryState = 0x00000001, + eVisibleRegion = 0x00000002, }; |