summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Agopian <mathias@google.com>2012-05-23 17:56:42 -0700
committerMathias Agopian <mathias@google.com>2012-05-23 18:01:33 -0700
commit2c8207e9627fe6c7a90e31fae8d71ae49df56845 (patch)
tree7a03095f78529e8b9f519530effce170b4921715
parent702634a4dad85cfc292618ac91eda6c00f42b7c5 (diff)
downloadnative-2c8207e9627fe6c7a90e31fae8d71ae49df56845.tar.gz
add the ability to reject buffers in SurfaceTexture::updateTexImage
SurfaceFlinger is using this new feature to reject buffers that don't have the right size. Bug: 6498869 Change-Id: I8a7250a47db6c082a357b703feb3b9d0fc8d3443
-rw-r--r--include/gui/SurfaceTexture.h13
-rw-r--r--libs/gui/SurfaceTexture.cpp14
-rw-r--r--services/surfaceflinger/Layer.cpp162
3 files changed, 122 insertions, 67 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 5e527cd09e..d07a4b6852 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -527,86 +527,113 @@ 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;
}
+
// update the active buffer
mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
- uint32_t bufWidth = mActiveBuffer->getWidth();
- uint32_t bufHeight = mActiveBuffer->getHeight();
- const uint32_t transform(mSurfaceTexture->getCurrentTransform());
- const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode());
-
- // 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);
- }
-
- // update the layer size if needed
- const Layer::State& front(drawingState());
-
- if (front.active != front.requested) {
- bool isFixedSize = scalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
-
- 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& editFront(mDrawingState);
- editFront.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.
- Layer::State& editCurrent(currentState());
- editCurrent.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, transform, scalingMode,
- 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());
- }
-
mFrameLatencyNeeded = true;
-
if (oldActiveBuffer == NULL && mActiveBuffer != NULL) {
- // the first time we receive a buffer, we need to trigger a
- // geometry invalidation.
- mFlinger->invalidateHwcGeometry();
- }
+ // the first time we receive a buffer, we need to trigger a
+ // geometry invalidation.
+ mFlinger->invalidateHwcGeometry();
+ }
+ uint32_t bufWidth = mActiveBuffer->getWidth();
+ uint32_t bufHeight = mActiveBuffer->getHeight();
Rect crop(mSurfaceTexture->getCurrentCrop());
+ const uint32_t transform(mSurfaceTexture->getCurrentTransform());
+ const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode());
if ((crop != mCurrentCrop) ||
(transform != mCurrentTransform) ||
(scalingMode != mCurrentScalingMode))
@@ -630,6 +657,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
}
// FIXME: mPostedDirtyRegion = dirty & bounds
+ const Layer::State& front(drawingState());
mPostedDirtyRegion.set(front.active.w, front.active.h);
glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);