diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 622724e5f..66c390a84 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -172,6 +172,10 @@ public: // getCurrentScalingMode returns the scaling mode of the current buffer. uint32_t getCurrentScalingMode() const; + // getCurrentFence returns the fence indicating when the current buffer is + // ready to be read from. + sp getCurrentFence() const; + // isSynchronousMode returns whether the SurfaceTexture is currently in // synchronous mode. bool isSynchronousMode() const; @@ -303,6 +307,9 @@ private: // set to each time updateTexImage is called. uint32_t mCurrentScalingMode; + // mCurrentFence is the fence received from BufferQueue in updateTexImage. + sp mCurrentFence; + // mCurrentTransformMatrix is the transform matrix for the current texture. // It gets computed by computeTransformMatrix each time updateTexImage is // called. diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 435a66559..9c76e6e78 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -260,14 +260,6 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) { } } - // Temporary; fence will be provided to clients soon - if (item.mFence.get()) { - err = item.mFence->wait(Fence::TIMEOUT_NEVER); - if (err != OK) { - ST_LOGE("updateTexImage: failure waiting for fence: %d", err); - } - } - if (err == NO_ERROR) { GLint error; while ((error = glGetError()) != GL_NO_ERROR) { @@ -322,6 +314,7 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) { mCurrentTransform = item.mTransform; mCurrentScalingMode = item.mScalingMode; mCurrentTimestamp = item.mTimestamp; + mCurrentFence = item.mFence; computeCurrentTransformMatrix(); } else { if (err < 0) { @@ -733,6 +726,11 @@ uint32_t SurfaceTexture::getCurrentScalingMode() const { return mCurrentScalingMode; } +sp SurfaceTexture::getCurrentFence() const { + Mutex::Autolock lock(mMutex); + return mCurrentFence; +} + bool SurfaceTexture::isSynchronousMode() const { Mutex::Autolock lock(mMutex); return mBufferQueue->isSynchronousMode(); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 7c09ab2f0..4ed692fc4 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -350,6 +350,12 @@ public: // not supported on VERSION_03 return -1; } + virtual void setAcquireFenceFd(int fenceFd) { + if (fenceFd != -1) { + ALOGE("HWC 0.x can't handle acquire fences"); + close(fenceFd); + } + } virtual void setDefaultState() { getLayer()->compositionType = HWC_FRAMEBUFFER; @@ -416,6 +422,9 @@ public: getLayer()->releaseFenceFd = -1; return fd; } + virtual void setAcquireFenceFd(int fenceFd) { + getLayer()->acquireFenceFd = fenceFd; + } virtual void setDefaultState() { getLayer()->compositionType = HWC_FRAMEBUFFER; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index cb4c2db8a..a662b25f4 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -109,6 +109,7 @@ public: virtual void setCrop(const Rect& crop) = 0; virtual void setVisibleRegionScreen(const Region& reg) = 0; virtual void setBuffer(const sp& buffer) = 0; + virtual void setAcquireFenceFd(int fenceFd) = 0; }; /* diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 6aba16a5c..5b9327dd6 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -60,6 +60,7 @@ Layer::Layer(SurfaceFlinger* flinger, mCurrentOpacity(true), mRefreshPending(false), mFrameLatencyNeeded(false), + mNeedHwcFence(false), mFrameLatencyOffset(0), mFormat(PIXEL_FORMAT_NONE), mGLExtensions(GLExtensions::getInstance()), @@ -299,6 +300,20 @@ void Layer::setPerFrameData(HWComposer::HWCLayerInterface& layer) { // NOTE: buffer can be NULL if the client never drew into this // layer yet, or if we ran out of memory layer.setBuffer(buffer); + + if (mNeedHwcFence) { + sp fence = mSurfaceTexture->getCurrentFence(); + if (fence.get()) { + int fenceFd = fence->dup(); + if (fenceFd == -1) { + ALOGW("failed to dup layer fence, skipping sync: %d", errno); + } + layer.setAcquireFenceFd(fenceFd); + } + mNeedHwcFence = false; + } else { + layer.setAcquireFenceFd(-1); + } } void Layer::onDraw(const DisplayHardware& hw, const Region& clip) const @@ -333,6 +348,15 @@ void Layer::onDraw(const DisplayHardware& hw, const Region& clip) const return; } + // TODO: replace this with a server-side wait + sp fence = mSurfaceTexture->getCurrentFence(); + if (fence.get()) { + status_t err = fence->wait(Fence::TIMEOUT_NEVER); + ALOGW_IF(err != OK, "Layer::onDraw: failed waiting for fence: %d", err); + // Go ahead and draw the buffer anyway; no matter what we do the screen + // is probably going to have something visibly wrong. + } + if (!isProtected()) { // TODO: we could be more subtle with isFixedSize() const bool useFiltering = getFiltering() || needsFiltering() || isFixedSize(); @@ -627,6 +651,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) mRefreshPending = true; mFrameLatencyNeeded = true; + mNeedHwcFence = true; if (oldActiveBuffer == NULL) { // the first time we receive a buffer, we need to trigger a // geometry invalidation. diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index d47f2e850..29515f04c 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -120,6 +120,7 @@ private: bool mCurrentOpacity; bool mRefreshPending; bool mFrameLatencyNeeded; + bool mNeedHwcFence; int mFrameLatencyOffset; struct Statistics {