Avoid unnecessary texture bind

In SurfaceFlingerConsumer, check to see if native fence sync is
enabled.  If so, defer the texture binding step to Layer::onDraw.

Change-Id: I7d4034a31c0143207eea2509dfa13ef3820f9b8c
This commit is contained in:
Andy McFadden 2012-12-11 15:21:45 -08:00
parent 3325fe16e6
commit 97eba8904c
5 changed files with 51 additions and 40 deletions

View File

@ -243,13 +243,9 @@ protected:
status_t releaseAndUpdateLocked(const BufferQueue::BufferItem& item);
// Binds mTexName and the current buffer to mTexTarget. Uses
// mCurrentTexture if it's set, mCurrentTextureBuf if not.
status_t bindTextureImage();
// doGLFenceWaitLocked inserts a wait command into the OpenGL ES command
// stream to ensure that it is safe for future OpenGL ES commands to
// access the current texture buffer.
status_t doGLFenceWaitLocked() const;
// mCurrentTexture if it's set, mCurrentTextureBuf if not. If the
// bind succeeds, this calls doGLFenceWait.
status_t bindTextureImageLocked();
// Gets the current EGLDisplay and EGLContext values, and compares them
// to mEglDisplay and mEglContext. If the fields have been previously
@ -257,6 +253,10 @@ protected:
// values.
status_t checkAndUpdateEglStateLocked();
// If set, SurfaceTexture will use the EGL_ANDROID_native_fence_sync
// extension to create Android native fences for GLES activity.
static const bool sUseNativeFenceSync;
private:
// createImage creates a new EGLImage from a GraphicBuffer.
EGLImageKHR createImage(EGLDisplay dpy,
@ -275,6 +275,11 @@ private:
// mCurrentTextureBuf must not be NULL.
void computeCurrentTransformMatrixLocked();
// doGLFenceWaitLocked inserts a wait command into the OpenGL ES command
// stream to ensure that it is safe for future OpenGL ES commands to
// access the current texture buffer.
status_t doGLFenceWaitLocked() const;
// syncForReleaseLocked performs the synchronization needed to release the
// current slot from an OpenGL ES context. If needed it will set the
// current slot's fence to guard against a producer accessing the buffer

View File

@ -39,6 +39,8 @@
#include <utils/String8.h>
#include <utils/Trace.h>
namespace android {
// This compile option makes SurfaceTexture use the
// EGL_ANDROID_native_fence_sync extension to create Android native fences to
// signal when all GLES reads for a given buffer have completed. It is not
@ -48,9 +50,9 @@
#ifdef USE_FENCE_SYNC
#error "USE_NATIVE_FENCE_SYNC and USE_FENCE_SYNC are incompatible"
#endif
static const bool useNativeFenceSync = true;
const bool SurfaceTexture::sUseNativeFenceSync = true;
#else
static const bool useNativeFenceSync = false;
const bool SurfaceTexture::sUseNativeFenceSync = false;
#endif
// This compile option makes SurfaceTexture use the EGL_ANDROID_sync_wait
@ -70,8 +72,6 @@ static const bool useWaitSync = false;
#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
namespace android {
// Transform matrices
static float mtxIdentity[16] = {
1, 0, 0, 0,
@ -196,14 +196,8 @@ status_t SurfaceTexture::updateTexImage() {
return err;
}
// Bind the new buffer to the GL texture.
err = bindTextureImage();
if (err != NO_ERROR) {
return err;
}
// Wait for the new buffer to be ready.
return doGLFenceWaitLocked();
// Bind the new buffer to the GL texture, and wait until it's ready.
return bindTextureImageLocked();
}
status_t SurfaceTexture::acquireBufferLocked(BufferQueue::BufferItem *item) {
@ -313,7 +307,7 @@ status_t SurfaceTexture::releaseAndUpdateLocked(const BufferQueue::BufferItem& i
return err;
}
status_t SurfaceTexture::bindTextureImage() {
status_t SurfaceTexture::bindTextureImageLocked() {
if (mEglDisplay == EGL_NO_DISPLAY) {
ALOGE("bindTextureImage: invalid display");
return INVALID_OPERATION;
@ -330,7 +324,10 @@ status_t SurfaceTexture::bindTextureImage() {
ST_LOGE("bindTextureImage: no currently-bound texture");
return NO_INIT;
}
return bindUnslottedBufferLocked(mEglDisplay);
status_t err = bindUnslottedBufferLocked(mEglDisplay);
if (err != NO_ERROR) {
return err;
}
} else {
EGLImageKHR image = mEglSlots[mCurrentTexture].mEglImage;
@ -341,8 +338,11 @@ status_t SurfaceTexture::bindTextureImage() {
": %#04x", image, error);
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
// Wait for the new buffer to be ready.
return doGLFenceWaitLocked();
}
status_t SurfaceTexture::checkAndUpdateEglStateLocked() {
@ -521,7 +521,7 @@ status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) {
ST_LOGV("syncForReleaseLocked");
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
if (useNativeFenceSync) {
if (sUseNativeFenceSync) {
EGLSyncKHR sync = eglCreateSyncKHR(dpy,
EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
if (sync == EGL_NO_SYNC_KHR) {

View File

@ -327,17 +327,11 @@ void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const
return;
}
// Bind the current buffer to the GL texture.
// Bind the current buffer to the GL texture, and wait for it to be
// ready for us to draw into.
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);
ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
// Go ahead and draw the buffer anyway; no matter what we do the screen
// is probably going to have something visibly wrong.
}

View File

@ -77,12 +77,24 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter)
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();
if (!sUseNativeFenceSync) {
// Bind the new buffer to the GL texture.
//
// Older devices require the "implicit" synchronization provided
// by glEGLImageTargetTexture2DOES, which this method calls. Newer
// devices will either call this in Layer::onDraw, or (if it's not
// a GL-composited layer) not at all.
err = bindTextureImageLocked();
}
return err;
}
status_t SurfaceFlingerConsumer::bindTextureImage()
{
Mutex::Autolock lock(mMutex);
return bindTextureImageLocked();
}
// ---------------------------------------------------------------------------

View File

@ -49,8 +49,8 @@ public:
// texture.
status_t updateTexImage(BufferRejecter* rejecter);
// Pass-through to SurfaceTexture implementation.
status_t bindTextureImage() { return SurfaceTexture::bindTextureImage(); }
// See SurfaceTexture::bindTextureImageLocked().
status_t bindTextureImage();
};
// ----------------------------------------------------------------------------