Merge "Support looper callbacks based on smart pointers." into jb-dev
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index f9cf0be..2635e2f 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -236,6 +236,19 @@
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 30c0d9b..55be4bc 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -176,6 +176,10 @@
}
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 @@
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 6ec4f49..5e17d07 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -428,38 +428,51 @@
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 @@
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 @@
// 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 @@
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 @@
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 7c6a28a..16bac8f 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -201,12 +201,14 @@
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 9542424..c547a40 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -227,7 +227,8 @@
enum { // flags for doTransaction()
- eVisibleRegion = 0x00000002,
+ eDontUpdateGeometryState = 0x00000001,
+ eVisibleRegion = 0x00000002,
};