Refactor SurfaceTexture a bit.
Rearranges updateTexImage() so that the SurfaceFlinger-specific
behavior is in a new SurfaceFlingerConsumer subclass.
SurfaceTexture behavior should not be altered. Instead of
acquire-bind-release we now do acquire-release-bind, but since
it's all done with the lock held there shouldn't be any
externally-visible change.
Change-Id: Ia566e4727945e2cfb9359fc6d2a8f8af64d7b7b7
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 329bbd5..f7870f4 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -17,6 +17,7 @@
GLExtensions.cpp \
MessageQueue.cpp \
SurfaceFlinger.cpp \
+ SurfaceFlingerConsumer.cpp \
SurfaceTextureLayer.cpp \
Transform.cpp \
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b6aa005..1c5403f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -73,7 +73,7 @@
HWComposer::HWCLayerInterface* layer) {
LayerBaseClient::onLayerDisplayed(hw, layer);
if (layer) {
- mSurfaceTexture->setReleaseFence(layer->getAndResetReleaseFenceFd());
+ mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFenceFd());
}
}
@@ -81,20 +81,20 @@
{
LayerBaseClient::onFirstRef();
- // Creates a custom BufferQueue for SurfaceTexture to use
+ // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<BufferQueue> bq = new SurfaceTextureLayer();
- mSurfaceTexture = new SurfaceTexture(mTextureName, true,
+ mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mTextureName, true,
GL_TEXTURE_EXTERNAL_OES, false, bq);
- mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0));
- mSurfaceTexture->setFrameAvailableListener(this);
- mSurfaceTexture->setSynchronousMode(true);
+ mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+ mSurfaceFlingerConsumer->setFrameAvailableListener(this);
+ mSurfaceFlingerConsumer->setSynchronousMode(true);
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
- mSurfaceTexture->setDefaultMaxBufferCount(2);
+ mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
#else
- mSurfaceTexture->setDefaultMaxBufferCount(3);
+ mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3);
#endif
const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
@@ -115,12 +115,12 @@
// in the purgatory list
void Layer::onRemoved()
{
- mSurfaceTexture->abandon();
+ mSurfaceFlingerConsumer->abandon();
}
void Layer::setName(const String8& name) {
LayerBase::setName(name);
- mSurfaceTexture->setName(name);
+ mSurfaceFlingerConsumer->setName(name);
}
sp<ISurface> Layer::createSurface()
@@ -131,7 +131,7 @@
sp<ISurfaceTexture> res;
sp<const Layer> that( mOwner.promote() );
if (that != NULL) {
- res = that->mSurfaceTexture->getBufferQueue();
+ res = that->mSurfaceFlingerConsumer->getBufferQueue();
}
return res;
}
@@ -146,7 +146,7 @@
wp<IBinder> Layer::getSurfaceTextureBinder() const
{
- return mSurfaceTexture->getBufferQueue()->asBinder();
+ return mSurfaceFlingerConsumer->getBufferQueue()->asBinder();
}
status_t Layer::setBuffers( uint32_t w, uint32_t h,
@@ -177,15 +177,15 @@
mOpaqueLayer = (flags & ISurfaceComposerClient::eOpaque);
mCurrentOpacity = getOpacityForFormat(format);
- mSurfaceTexture->setDefaultBufferSize(w, h);
- mSurfaceTexture->setDefaultBufferFormat(format);
- mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0));
+ mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
+ mSurfaceFlingerConsumer->setDefaultBufferFormat(format);
+ mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
return NO_ERROR;
}
Rect Layer::computeBufferCrop() const {
- // Start with the SurfaceTexture's buffer crop...
+ // Start with the SurfaceFlingerConsumer's buffer crop...
Rect crop;
if (!mCurrentCrop.isEmpty()) {
crop = mCurrentCrop;
@@ -202,7 +202,7 @@
if (!s.active.crop.isEmpty()) {
// Transform the window crop to match the buffer coordinate system,
// which means using the inverse of the current transform set on the
- // SurfaceTexture.
+ // SurfaceFlingerConsumer.
uint32_t invTransform = mCurrentTransform;
int winWidth = s.active.w;
int winHeight = s.active.h;
@@ -284,7 +284,7 @@
// acquire fence the first time a new buffer is acquired on EACH display.
if (layer.getCompositionType() == HWC_OVERLAY) {
- sp<Fence> fence = mSurfaceTexture->getCurrentFence();
+ sp<Fence> fence = mSurfaceFlingerConsumer->getCurrentFence();
if (fence.get()) {
fenceFd = fence->dup();
if (fenceFd == -1) {
@@ -327,7 +327,15 @@
return;
}
- status_t err = mSurfaceTexture->doGLFenceWait();
+ // Bind the current buffer to the GL texture.
+ status_t err = mSurfaceFlingerConsumer->bindTextureImage();
+ if (err != NO_ERROR) {
+ ALOGW("Layer::onDraw: bindTextureImage failed");
+ // keep going
+ }
+
+ // Wait for the buffer to be ready for us to draw into.
+ err = mSurfaceFlingerConsumer->doGLFenceWait();
if (err != OK) {
ALOGE("onDraw: failed waiting for fence: %d", err);
// Go ahead and draw the buffer anyway; no matter what we do the screen
@@ -342,8 +350,8 @@
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
- mSurfaceTexture->setFilteringEnabled(useFiltering);
- mSurfaceTexture->getTransformMatrix(textureMatrix);
+ mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
+ mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
// Set things up for texturing.
glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureName);
@@ -462,7 +470,7 @@
// record the new size, form this point on, when the client request
// a buffer, it'll get the new size.
- mSurfaceTexture->setDefaultBufferSize(
+ mSurfaceFlingerConsumer->setDefaultBufferSize(
temp.requested.w, temp.requested.h);
}
@@ -507,13 +515,10 @@
void Layer::onPostComposition() {
if (mFrameLatencyNeeded) {
- nsecs_t desiredPresentTime = mSurfaceTexture->getTimestamp();
+ nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp();
mFrameTracker.setDesiredPresentTime(desiredPresentTime);
- sp<Fence> frameReadyFence = mSurfaceTexture->getCurrentFence();
- // XXX: Temporarily don't use the fence from the SurfaceTexture to
- // work around a driver bug.
- frameReadyFence.clear();
+ sp<Fence> frameReadyFence = mSurfaceFlingerConsumer->getCurrentFence();
if (frameReadyFence != NULL) {
mFrameTracker.setFrameReadyFence(frameReadyFence);
} else {
@@ -570,7 +575,7 @@
mFlinger->signalLayerUpdate();
}
- struct Reject : public SurfaceTexture::BufferRejecter {
+ struct Reject : public SurfaceFlingerConsumer::BufferRejecter {
Layer::State& front;
Layer::State& current;
bool& recomputeVisibleRegions;
@@ -655,14 +660,14 @@
Reject r(mDrawingState, currentState(), recomputeVisibleRegions);
- if (mSurfaceTexture->updateTexImage(&r, true) < NO_ERROR) {
+ if (mSurfaceFlingerConsumer->updateTexImage(&r) != NO_ERROR) {
// something happened!
recomputeVisibleRegions = true;
return outDirtyRegion;
}
// update the active buffer
- mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
+ mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer();
if (mActiveBuffer == NULL) {
// this can only happen if the very first buffer was rejected.
return outDirtyRegion;
@@ -676,9 +681,9 @@
recomputeVisibleRegions = true;
}
- Rect crop(mSurfaceTexture->getCurrentCrop());
- const uint32_t transform(mSurfaceTexture->getCurrentTransform());
- const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode());
+ Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
+ const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
+ const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
if ((crop != mCurrentCrop) ||
(transform != mCurrentTransform) ||
(scalingMode != mCurrentScalingMode))
@@ -737,8 +742,8 @@
result.append(buffer);
- if (mSurfaceTexture != 0) {
- mSurfaceTexture->dump(result, " ", buffer, SIZE);
+ if (mSurfaceFlingerConsumer != 0) {
+ mSurfaceFlingerConsumer->dump(result, " ", buffer, SIZE);
}
}
@@ -780,7 +785,7 @@
orientation = 0;
}
}
- mSurfaceTexture->setTransformHint(orientation);
+ mSurfaceFlingerConsumer->setTransformHint(orientation);
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 5ea3eb4..2d4afc4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -20,8 +20,6 @@
#include <stdint.h>
#include <sys/types.h>
-#include <gui/SurfaceTexture.h>
-
#include <utils/Timers.h>
#include <ui/GraphicBuffer.h>
@@ -34,6 +32,7 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
+#include "SurfaceFlingerConsumer.h"
#include "FrameTracker.h"
#include "LayerBase.h"
#include "SurfaceTextureLayer.h"
@@ -49,7 +48,7 @@
// ---------------------------------------------------------------------------
class Layer : public LayerBaseClient,
- public SurfaceTexture::FrameAvailableListener
+ public SurfaceFlingerConsumer::FrameAvailableListener
{
public:
Layer(SurfaceFlinger* flinger, const sp<Client>& client);
@@ -92,7 +91,7 @@
// only for debugging
inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
- // Updates the transform hint in our SurfaceTexture to match
+ // Updates the transform hint in our SurfaceFlingerConsumer to match
// the current orientation of the display device.
virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const;
@@ -110,13 +109,13 @@
Rect computeBufferCrop() const;
static bool getOpacityForFormat(uint32_t format);
- // Interface implementation for SurfaceTexture::FrameAvailableListener
+ // Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener
virtual void onFrameAvailable();
// -----------------------------------------------------------------------
// constants
- sp<SurfaceTexture> mSurfaceTexture;
+ sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer;
GLuint mTextureName;
// thread-safe
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
new file mode 100644
index 0000000..dbe187b
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "SurfaceFlingerConsumer.h"
+
+#include <utils/Trace.h>
+#include <utils/Errors.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter)
+{
+ ATRACE_CALL();
+ ALOGV("updateTexImage");
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ ALOGE("updateTexImage: SurfaceTexture is abandoned!");
+ return NO_INIT;
+ }
+
+ // Make sure the EGL state is the same as in previous calls.
+ status_t err = checkAndUpdateEglStateLocked();
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ BufferQueue::BufferItem item;
+
+ // Acquire the next buffer.
+ // In asynchronous mode the list is guaranteed to be one buffer
+ // deep, while in synchronous mode we use the oldest buffer.
+ err = acquireBufferLocked(&item);
+ if (err != NO_ERROR) {
+ if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+ // This variant of updateTexImage does not guarantee that the
+ // texture is bound, so no need to call glBindTexture.
+ err = NO_ERROR;
+ } else {
+ ALOGE("updateTexImage: acquire failed: %s (%d)",
+ strerror(-err), err);
+ }
+ return err;
+ }
+
+
+ // 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
+ int buf = item.mBuf;
+ if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
+ releaseBufferLocked(buf, EGL_NO_SYNC_KHR);
+ return NO_ERROR;
+ }
+
+ // Release the previous buffer.
+ err = releaseAndUpdateLocked(item);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ // Bind the new buffer to the GL texture.
+ // TODO: skip this on devices that support explicit sync
+ // (glEGLImageTargetTexture2DOES provides required implicit sync;
+ // without this we get wedged on older devices, but newer devices
+ // don't need it.)
+ return bindTextureImage();
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
new file mode 100644
index 0000000..d91f27e
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SURFACEFLINGERCONSUMER_H
+#define ANDROID_SURFACEFLINGERCONSUMER_H
+
+#include <gui/SurfaceTexture.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+/*
+ * This is a thin wrapper around SurfaceTexture.
+ */
+class SurfaceFlingerConsumer : public SurfaceTexture {
+public:
+ SurfaceFlingerConsumer(GLuint tex, bool allowSynchronousMode = true,
+ GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true,
+ const sp<BufferQueue> &bufferQueue = 0)
+ : SurfaceTexture(tex, allowSynchronousMode, texTarget, useFenceSync,
+ bufferQueue)
+ {}
+
+ class BufferRejecter {
+ friend class SurfaceFlingerConsumer;
+ virtual bool reject(const sp<GraphicBuffer>& buf,
+ const BufferQueue::BufferItem& item) = 0;
+
+ protected:
+ virtual ~BufferRejecter() { }
+ };
+
+ // This version of updateTexImage() takes a functor that may be used to
+ // reject the newly acquired buffer. Unlike the SurfaceTexture version,
+ // this does not guarantee that the buffer has been bound to the GL
+ // texture.
+ status_t updateTexImage(BufferRejecter* rejecter);
+
+ // Pass-through to SurfaceTexture implementation.
+ status_t bindTextureImage() { return SurfaceTexture::bindTextureImage(); }
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SURFACEFLINGERCONSUMER_H