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:
parent
3325fe16e6
commit
97eba8904c
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue