diff options
Diffstat (limited to 'services/surfaceflinger')
25 files changed, 341 insertions, 175 deletions
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index f7d32d0..49389e0 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -93,7 +93,7 @@ status_t Client::onTransact( const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); const int self_pid = getpid(); - if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) { + if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != 0)) { // we're called from a different process, do the real check if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger)) { diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp index a000a84..659c2c8 100644 --- a/services/surfaceflinger/DdmConnection.cpp +++ b/services/surfaceflinger/DdmConnection.cpp @@ -66,7 +66,7 @@ void DdmConnection::start(const char* name) { jint (*registerNatives)(JNIEnv* env, jclass clazz); registerNatives = reinterpret_cast<decltype(registerNatives)>( dlsym(libandroid_runtime_dso, - "Java_com_android_internal_util_WithFramework_registerNatives")); + "Java_com_android_internal_util_WithFramework_registerNatives")); ALOGE_IF(!registerNatives, "DdmConnection: %s", dlerror()); if (!JNI_CreateJavaVM || !registerNatives) { diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h index 96efc34..67142b6 100644 --- a/services/surfaceflinger/DispSync.h +++ b/services/surfaceflinger/DispSync.h @@ -139,7 +139,7 @@ private: enum { MAX_RESYNC_SAMPLES = 32 }; enum { MIN_RESYNC_SAMPLES_FOR_UPDATE = 3 }; enum { NUM_PRESENT_SAMPLES = 8 }; - enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 12 }; + enum { MAX_RESYNC_SAMPLES_WITHOUT_PRESENT = 4 }; // mPeriod is the computed period of the modeled vsync events in // nanoseconds. diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index c8b36ec..2dad005 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -305,13 +305,16 @@ void HWComposer::vsync(int disp, int64_t timestamp) { } void HWComposer::hotplug(int disp, int connected) { - if (disp == HWC_DISPLAY_PRIMARY || disp >= VIRTUAL_DISPLAY_ID_BASE) { + if (disp >= VIRTUAL_DISPLAY_ID_BASE) { ALOGE("hotplug event received for invalid display: disp=%d connected=%d", disp, connected); return; } queryDisplayProperties(disp); - mEventHandler.onHotplugReceived(disp, bool(connected)); + // Do not teardown or recreate the primary display + if (disp != HWC_DISPLAY_PRIMARY) { + mEventHandler.onHotplugReceived(disp, bool(connected)); + } } static float getDefaultDensity(uint32_t width, uint32_t height) { @@ -461,7 +464,7 @@ sp<Fence> HWComposer::getDisplayFence(int disp) const { } uint32_t HWComposer::getFormat(int disp) const { - if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) { + if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) { return HAL_PIXEL_FORMAT_RGBA_8888; } else { return mDisplayData[disp].format; @@ -632,6 +635,7 @@ status_t HWComposer::setFramebufferTarget(int32_t id, } status_t HWComposer::prepare() { + Mutex::Autolock _l(mDisplayLock); for (size_t i=0 ; i<mNumDisplays ; i++) { DisplayData& disp(mDisplayData[i]); if (disp.framebufferTarget) { @@ -1142,6 +1146,7 @@ static String8 getFormatStr(PixelFormat format) { } void HWComposer::dump(String8& result) const { + Mutex::Autolock _l(mDisplayLock); if (mHwc) { result.appendFormat("Hardware Composer state (version %08x):\n", hwcApiVersion(mHwc)); result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 28d8c65..cc98b4c 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -354,6 +354,8 @@ private: // mLists[i>0] can be NULL. that display is to be ignored struct hwc_display_contents_1* mLists[MAX_HWC_DISPLAYS]; DisplayData mDisplayData[MAX_HWC_DISPLAYS]; + // protect mDisplayData from races between prepare and dump + mutable Mutex mDisplayLock; size_t mNumDisplays; cb_context* mCBContext; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 11cbdc6..ba4c198 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -530,6 +530,15 @@ status_t VirtualDisplaySurface::allowAllocation(bool /* allow */) { return INVALID_OPERATION; } +status_t VirtualDisplaySurface::setGenerationNumber(uint32_t /* generation */) { + ALOGE("setGenerationNumber not supported on VirtualDisplaySurface"); + return INVALID_OPERATION; +} + +String8 VirtualDisplaySurface::getConsumerName() const { + return String8("VirtualDisplaySurface"); +} + void VirtualDisplaySurface::updateQueueBufferOutput( const QueueBufferOutput& qbo) { uint32_t w, h, transformHint, numPendingBuffers; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 97af980..6298751 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -116,6 +116,8 @@ private: virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage); virtual status_t allowAllocation(bool allow); + virtual status_t setGenerationNumber(uint32_t generationNumber); + virtual String8 getConsumerName() const override; // // Utility methods diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 2944c63..5ff79a9 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -76,11 +76,15 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mFiltering(false), mNeedsFiltering(false), mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2), - mSecure(false), mProtectedByApp(false), mHasSurface(false), mClientRef(client), - mPotentialCursor(false) + mPotentialCursor(false), + mQueueItemLock(), + mQueueItemCondition(), + mQueueItems(), + mLastFrameNumberReceived(0), + mUpdateTexImageFailed(false) { mCurrentCrop.makeInvalid(); mFlinger->getRenderEngine().genTextures(1, &mTextureName); @@ -91,6 +95,8 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, layerFlags |= layer_state_t::eLayerHidden; if (flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque; + if (flags & ISurfaceComposerClient::eSecure) + layerFlags |= layer_state_t::eLayerSecure; if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false; @@ -163,20 +169,54 @@ void Layer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker { // Autolock scope Mutex::Autolock lock(mQueueItemLock); + + // Reset the frame number tracker when we receive the first buffer after + // a frame number reset + if (item.mFrameNumber == 1) { + mLastFrameNumberReceived = 0; + } + + // Ensure that callbacks are handled in order + while (item.mFrameNumber != mLastFrameNumberReceived + 1) { + status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, + ms2ns(500)); + if (result != NO_ERROR) { + ALOGE("[%s] Timed out waiting on callback", mName.string()); + } + } + mQueueItems.push_back(item); + android_atomic_inc(&mQueuedFrames); + + // Wake up any pending callbacks + mLastFrameNumberReceived = item.mFrameNumber; + mQueueItemCondition.broadcast(); } - android_atomic_inc(&mQueuedFrames); mFlinger->signalLayerUpdate(); } void Layer::onFrameReplaced(const BufferItem& item) { Mutex::Autolock lock(mQueueItemLock); + + // Ensure that callbacks are handled in order + while (item.mFrameNumber != mLastFrameNumberReceived + 1) { + status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, + ms2ns(500)); + if (result != NO_ERROR) { + ALOGE("[%s] Timed out waiting on callback", mName.string()); + } + } + if (mQueueItems.empty()) { ALOGE("Can't replace a frame on an empty queue"); return; } mQueueItems.editItemAt(0) = item; + + // Wake up any pending callbacks + mLastFrameNumberReceived = item.mFrameNumber; + mQueueItemCondition.broadcast(); } void Layer::onSidebandStreamChanged() { @@ -217,7 +257,6 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, mFormat = format; mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false; - mSecure = (flags & ISurfaceComposerClient::eSecure) ? true : false; mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false; mCurrentOpacity = getOpacityForFormat(format); @@ -512,16 +551,7 @@ void Layer::setPerFrameData(const sp<const DisplayDevice>& hw, const Transform& tr = hw->getTransform(); Region visible = tr.transform(visibleRegion.intersect(hw->getViewport())); layer.setVisibleRegionScreen(visible); - - // Pass full-surface damage down untouched - if (surfaceDamageRegion.isRect() && - surfaceDamageRegion.getBounds() == Rect::INVALID_RECT) { - layer.setSurfaceDamage(surfaceDamageRegion); - } else { - Region surfaceDamage = - tr.transform(surfaceDamageRegion.intersect(hw->getViewport())); - layer.setSurfaceDamage(surfaceDamage); - } + layer.setSurfaceDamage(surfaceDamageRegion); if (mSidebandStream.get()) { layer.setSidebandStream(mSidebandStream); @@ -821,6 +851,12 @@ bool Layer::isOpaque(const Layer::State& s) const return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity; } +bool Layer::isSecure() const +{ + const Layer::State& s(mDrawingState); + return (s.flags & layer_state_t::eLayerSecure); +} + bool Layer::isProtected() const { const sp<GraphicBuffer>& activeBuffer(mActiveBuffer); @@ -1065,11 +1101,26 @@ void Layer::useEmptyDamage() { // ---------------------------------------------------------------------------- bool Layer::shouldPresentNow(const DispSync& dispSync) const { + if (mSidebandStreamChanged) { + return true; + } + Mutex::Autolock lock(mQueueItemLock); + if (mQueueItems.empty()) { + return false; + } + auto timestamp = mQueueItems[0].mTimestamp; nsecs_t expectedPresent = mSurfaceFlingerConsumer->computeExpectedPresent(dispSync); - return mQueueItems.empty() ? - false : mQueueItems[0].mTimestamp < expectedPresent; + + // Ignore timestamps more than a second in the future + bool isPlausible = timestamp < (expectedPresent + s2ns(1)); + ALOGW_IF(!isPlausible, "[%s] Timestamp %" PRId64 " seems implausible " + "relative to expectedPresent %" PRId64, mName.string(), timestamp, + expectedPresent); + + bool isDue = timestamp < expectedPresent; + return isDue || !isPlausible; } bool Layer::onPreComposition() { @@ -1120,6 +1171,10 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) { // mSidebandStreamChanged was true mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream(); + if (mSidebandStream != NULL) { + setTransactionFlags(eTransactionNeeded); + mFlinger->setTransactionFlags(eTraversalNeeded); + } recomputeVisibleRegions = true; const State& s(getDrawingState()); @@ -1252,21 +1307,62 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions, getProducerStickyTransform() != 0); + uint64_t maxFrameNumber = 0; + { + Mutex::Autolock lock(mQueueItemLock); + maxFrameNumber = mLastFrameNumberReceived; + } + status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r, - mFlinger->mPrimaryDispSync); + mFlinger->mPrimaryDispSync, maxFrameNumber); if (updateResult == BufferQueue::PRESENT_LATER) { // Producer doesn't want buffer to be displayed yet. Signal a // layer update so we check again at the next opportunity. mFlinger->signalLayerUpdate(); return outDirtyRegion; + } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) { + // If the buffer has been rejected, remove it from the shadow queue + // and return early + Mutex::Autolock lock(mQueueItemLock); + mQueueItems.removeAt(0); + android_atomic_dec(&mQueuedFrames); + return outDirtyRegion; + } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) { + // This can occur if something goes wrong when trying to create the + // EGLImage for this buffer. If this happens, the buffer has already + // been released, so we need to clean up the queue and bug out + // early. + { + Mutex::Autolock lock(mQueueItemLock); + mQueueItems.clear(); + android_atomic_and(0, &mQueuedFrames); + } + + // Once we have hit this state, the shadow queue may no longer + // correctly reflect the incoming BufferQueue's contents, so even if + // updateTexImage starts working, the only safe course of action is + // to continue to ignore updates. + mUpdateTexImageFailed = true; + + return outDirtyRegion; } - // Remove this buffer from our internal queue tracker { // Autolock scope + auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber(); + Mutex::Autolock lock(mQueueItemLock); + + // Remove any stale buffers that have been dropped during + // updateTexImage + while (mQueueItems[0].mFrameNumber != currentFrameNumber) { + mQueueItems.removeAt(0); + android_atomic_dec(&mQueuedFrames); + } + mQueueItems.removeAt(0); } + // Decrement the queued-frames count. Signal another event if we // have more frames pending. if (android_atomic_dec(&mQueuedFrames) > 1) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 46c17e5..c1e5e9f 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -174,7 +174,7 @@ public: * isSecure - true if this surface is secure, that is if it prevents * screenshots or VNC servers. */ - virtual bool isSecure() const { return mSecure; } + virtual bool isSecure() const; /* * isProtected - true if the layer may contain protected content in the @@ -339,9 +339,9 @@ protected: private: // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener - virtual void onFrameAvailable(const BufferItem& item); - virtual void onFrameReplaced(const BufferItem& item); - virtual void onSidebandStreamChanged(); + virtual void onFrameAvailable(const BufferItem& item) override; + virtual void onFrameReplaced(const BufferItem& item) override; + virtual void onSidebandStreamChanged() override; void commitTransaction(); @@ -402,7 +402,6 @@ private: mutable Texture mTexture; // page-flip thread (currently main thread) - bool mSecure; // no screenshots bool mProtectedByApp; // application requires protected path to external sink // protected by mLock @@ -416,7 +415,10 @@ private: // Local copy of the queued contents of the incoming BufferQueue mutable Mutex mQueueItemLock; + Condition mQueueItemCondition; Vector<BufferItem> mQueueItems; + uint64_t mLastFrameNumberReceived; + bool mUpdateTexImageFailed; // This is only modified from the main thread }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index 9fb555b..fb7af97 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -114,6 +114,14 @@ status_t MonitoredProducer::allowAllocation(bool allow) { return mProducer->allowAllocation(allow); } +status_t MonitoredProducer::setGenerationNumber(uint32_t generationNumber) { + return mProducer->setGenerationNumber(generationNumber); +} + +String8 MonitoredProducer::getConsumerName() const { + return mProducer->getConsumerName(); +} + IBinder* MonitoredProducer::onAsBinder() { return IInterface::asBinder(mProducer).get(); } diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index b2f8293..da95766 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -54,6 +54,8 @@ public: virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage); virtual status_t allowAllocation(bool allow); + virtual status_t setGenerationNumber(uint32_t generationNumber); + virtual String8 getConsumerName() const override; virtual IBinder* onAsBinder(); private: diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp index 1adcd1f..0dab872 100644 --- a/services/surfaceflinger/RenderEngine/Description.cpp +++ b/services/surfaceflinger/RenderEngine/Description.cpp @@ -88,5 +88,9 @@ void Description::setColorMatrix(const mat4& mtx) { mColorMatrixEnabled = (mtx != identity); } +const mat4& Description::getColorMatrix() const { + return mColorMatrix; +} + } /* namespace android */ diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h index 43b835f..8a3447c 100644 --- a/services/surfaceflinger/RenderEngine/Description.h +++ b/services/surfaceflinger/RenderEngine/Description.h @@ -66,6 +66,7 @@ public: void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); void setProjectionMatrix(const mat4& mtx); void setColorMatrix(const mat4& mtx); + const mat4& getColorMatrix() const; private: bool mUniformsDirty; diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp index 2e6af49..1a9f59b 100644 --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp @@ -262,14 +262,6 @@ void GLES11RenderEngine::drawMesh(const Mesh& mesh) { } } -void GLES11RenderEngine::beginGroup(const mat4& /*colorTransform*/) { - // doesn't do anything in GLES 1.1 -} - -void GLES11RenderEngine::endGroup() { - // doesn't do anything in GLES 1.1 -} - void GLES11RenderEngine::dump(String8& result) { RenderEngine::dump(result); } diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h index 87eb3e4..08de646 100644 --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h @@ -62,9 +62,6 @@ protected: virtual void drawMesh(const Mesh& mesh); - virtual void beginGroup(const mat4& colorTransform); - virtual void endGroup(); - virtual size_t getMaxTextureSize() const; virtual size_t getMaxViewportDims() const; }; diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp index 8712c9a..1fabaf5 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp @@ -169,6 +169,12 @@ void GLES20RenderEngine::setupLayerBlackedOut() { mState.setTexture(texture); } +mat4 GLES20RenderEngine::setupColorTransform(const mat4& colorTransform) { + mat4 oldTransform = mState.getColorMatrix(); + mState.setColorMatrix(colorTransform); + return oldTransform; +} + void GLES20RenderEngine::disableTexturing() { mState.disableTexture(); } @@ -237,78 +243,6 @@ void GLES20RenderEngine::drawMesh(const Mesh& mesh) { } } -void GLES20RenderEngine::beginGroup(const mat4& colorTransform) { - - GLuint tname, name; - // create the texture - glGenTextures(1, &tname); - glBindTexture(GL_TEXTURE_2D, tname); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mVpWidth, mVpHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - - // create a Framebuffer Object to render into - glGenFramebuffers(1, &name); - glBindFramebuffer(GL_FRAMEBUFFER, name); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); - - Group group; - group.texture = tname; - group.fbo = name; - group.width = mVpWidth; - group.height = mVpHeight; - group.colorTransform = colorTransform; - - mGroupStack.push(group); -} - -void GLES20RenderEngine::endGroup() { - - const Group group(mGroupStack.top()); - mGroupStack.pop(); - - // activate the previous render target - GLuint fbo = 0; - if (!mGroupStack.isEmpty()) { - fbo = mGroupStack.top().fbo; - } - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - // set our state - Texture texture(Texture::TEXTURE_2D, group.texture); - texture.setDimensions(group.width, group.height); - glBindTexture(GL_TEXTURE_2D, group.texture); - - mState.setPlaneAlpha(1.0f); - mState.setPremultipliedAlpha(true); - mState.setOpaque(false); - mState.setTexture(texture); - mState.setColorMatrix(group.colorTransform); - glDisable(GL_BLEND); - - Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2); - Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); - Mesh::VertexArray<vec2> texCoord(mesh.getTexCoordArray<vec2>()); - position[0] = vec2(0, 0); - position[1] = vec2(group.width, 0); - position[2] = vec2(group.width, group.height); - position[3] = vec2(0, group.height); - texCoord[0] = vec2(0, 0); - texCoord[1] = vec2(1, 0); - texCoord[2] = vec2(1, 1); - texCoord[3] = vec2(0, 1); - drawMesh(mesh); - - // reset color matrix - mState.setColorMatrix(mat4()); - - // free our fbo and texture - glDeleteFramebuffers(1, &group.fbo); - glDeleteTextures(1, &group.texture); -} - void GLES20RenderEngine::dump(String8& result) { RenderEngine::dump(result); } diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h index 3d6243e..819356a 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h @@ -72,14 +72,12 @@ protected: virtual void setupLayerTexturing(const Texture& texture); virtual void setupLayerBlackedOut(); virtual void setupFillWithColor(float r, float g, float b, float a); + virtual mat4 setupColorTransform(const mat4& colorTransform); virtual void disableTexturing(); virtual void disableBlending(); virtual void drawMesh(const Mesh& mesh); - virtual void beginGroup(const mat4& colorTransform); - virtual void endGroup(); - virtual size_t getMaxTextureSize() const; virtual size_t getMaxViewportDims() const; }; diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp index 3f50cb0..ffd9be2 100644 --- a/services/surfaceflinger/RenderEngine/Mesh.cpp +++ b/services/surfaceflinger/RenderEngine/Mesh.cpp @@ -16,14 +16,40 @@ #include "Mesh.h" +#include <utils/Log.h> + namespace android { Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize) : mVertexCount(vertexCount), mVertexSize(vertexSize), mTexCoordsSize(texCoordSize), mPrimitive(primitive) { - mVertices = new float[(vertexSize + texCoordSize) * vertexCount]; - mStride = mVertexSize + mTexCoordsSize; + if (vertexCount == 0) { + mVertices = new float[1]; + mVertices[0] = 0.0f; + mStride = 0; + return; + } + + size_t stride = vertexSize + texCoordSize; + size_t remainder = (stride * vertexCount) / vertexCount; + // Since all of the input parameters are unsigned, if stride is less than + // either vertexSize or texCoordSize, it must have overflowed. remainder + // will be equal to stride as long as stride * vertexCount doesn't overflow. + if ((stride < vertexSize) || (remainder != stride)) { + ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize, + texCoordSize); + mVertices = new float[1]; + mVertices[0] = 0.0f; + mVertexCount = 0; + mVertexSize = 0; + mTexCoordsSize = 0; + mStride = 0; + return; + } + + mVertices = new float[stride * vertexCount]; + mStride = stride; } Mesh::~Mesh() { diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp index 0de5cca..ba11259 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp +++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp @@ -199,10 +199,8 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { // un-premultiply if needed before linearization fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;"; } - fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(2.2));"; fs << "vec4 transformed = colorMatrix * vec4(gl_FragColor.rgb, 1);"; fs << "gl_FragColor.rgb = transformed.rgb/transformed.a;"; - fs << "gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / 2.2));"; if (!needs.isOpaque() && needs.isPremultiplied()) { // and re-premultiply if needed after gamma correction fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;"; diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index 8d7529c..31a961e 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -99,18 +99,16 @@ public: virtual void setupLayerBlackedOut() = 0; virtual void setupFillWithColor(float r, float g, float b, float a) = 0; + virtual mat4 setupColorTransform(const mat4& /* colorTransform */) { + return mat4(); + } + virtual void disableTexturing() = 0; virtual void disableBlending() = 0; // drawing virtual void drawMesh(const Mesh& mesh) = 0; - // grouping - // creates a color-transform group, everything drawn in the group will be - // transformed by the given color transform when endGroup() is called. - virtual void beginGroup(const mat4& colorTransform) = 0; - virtual void endGroup() = 0; - // queries virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index df4ac2e..de0f921 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -149,7 +149,11 @@ SurfaceFlinger::SurfaceFlinger() mPrimaryHWVsyncEnabled(false), mHWVsyncAvailable(false), mDaltonize(false), - mHasColorMatrix(false) + mHasColorMatrix(false), + mHasPoweredOff(false), + mFrameBuckets(), + mTotalTime(0), + mLastSwapTime(0) { ALOGI("SurfaceFlinger is starting"); @@ -546,7 +550,7 @@ bool SurfaceFlinger::authenticateSurfaceTexture( status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayInfo>* configs) { - if (configs == NULL) { + if ((configs == NULL) || (display.get() == NULL)) { return BAD_VALUE; } @@ -997,8 +1001,8 @@ void SurfaceFlinger::postComposition() } } + const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); if (kIgnorePresentFences) { - const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); if (hw->isDisplayOn()) { enableHardwareVsync(); } @@ -1017,6 +1021,26 @@ void SurfaceFlinger::postComposition() } mAnimFrameTracker.advanceFrame(); } + + if (hw->getPowerMode() == HWC_POWER_MODE_OFF) { + return; + } + + nsecs_t currentTime = systemTime(); + if (mHasPoweredOff) { + mHasPoweredOff = false; + } else { + nsecs_t period = mPrimaryDispSync.getPeriod(); + nsecs_t elapsedTime = currentTime - mLastSwapTime; + size_t numPeriods = static_cast<size_t>(elapsedTime / period); + if (numPeriods < NUM_BUCKETS - 1) { + mFrameBuckets[numPeriods] += elapsedTime; + } else { + mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime; + } + mTotalTime += elapsedTime; + } + mLastSwapTime = currentTime; } void SurfaceFlinger::rebuildLayerStacks() { @@ -1848,9 +1872,9 @@ void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw, if (mDaltonize) { colorMatrix = colorMatrix * mDaltonizer(); } - engine.beginGroup(colorMatrix); + mat4 oldMatrix = engine.setupColorTransform(colorMatrix); doComposeSurfaces(hw, dirtyRegion); - engine.endGroup(); + engine.setupColorTransform(oldMatrix); } // update the swap region and clear the dirty region @@ -1994,18 +2018,25 @@ void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, const Regio engine.fillRegionWithColor(region, height, 0, 0, 0, 0); } -void SurfaceFlinger::addClientLayer(const sp<Client>& client, +status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle, const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc) { + // add this layer to the current state list + { + Mutex::Autolock _l(mStateLock); + if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) { + return NO_MEMORY; + } + mCurrentState.layersSortedByZ.add(lbc); + mGraphicBufferProducerList.add(IInterface::asBinder(gbc)); + } + // attach this layer to the client client->attachLayer(handle, lbc); - // add this layer to the current state list - Mutex::Autolock _l(mStateLock); - mCurrentState.layersSortedByZ.add(lbc); - mGraphicBufferProducerList.add(IInterface::asBinder(gbc)); + return NO_ERROR; } status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) { @@ -2204,9 +2235,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (layer->setTransparentRegionHint(s.transparentRegion)) flags |= eTraversalNeeded; } - if ((what & layer_state_t::eVisibilityChanged) || - (what & layer_state_t::eOpacityChanged)) { - // TODO: should we just use an eFlagsChanged for this? + if (what & layer_state_t::eFlagsChanged) { if (layer->setFlags(s.flags, s.mask)) flags |= eTraversalNeeded; } @@ -2262,10 +2291,16 @@ status_t SurfaceFlinger::createLayer( break; } - if (result == NO_ERROR) { - addClientLayer(client, *handle, *gbp, layer); - setTransactionFlags(eTransactionNeeded); + if (result != NO_ERROR) { + return result; + } + + result = addClientLayer(client, *handle, *gbp, layer); + if (result != NO_ERROR) { + return result; } + + setTransactionFlags(eTransactionNeeded); return result; } @@ -2398,6 +2433,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, } mVisibleRegionsDirty = true; + mHasPoweredOff = true; repaintEverything(); } else if (mode == HWC_POWER_MODE_OFF) { if (type == DisplayDevice::DISPLAY_PRIMARY) { @@ -2498,6 +2534,13 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) mPrimaryDispSync.dump(result); dumpAll = false; } + + if ((index < numArgs) && + (args[index] == String16("--static-screen"))) { + index++; + dumpStaticScreenStats(result); + dumpAll = false; + } } if (dumpAll) { @@ -2601,6 +2644,23 @@ void SurfaceFlinger::logFrameStats() { result.append(config); } +void SurfaceFlinger::dumpStaticScreenStats(String8& result) const +{ + result.appendFormat("Static screen stats:\n"); + for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) { + float bucketTimeSec = mFrameBuckets[b] / 1e9; + float percent = 100.0f * + static_cast<float>(mFrameBuckets[b]) / mTotalTime; + result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n", + b + 1, bucketTimeSec, percent); + } + float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9; + float percent = 100.0f * + static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime; + result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n", + NUM_BUCKETS - 1, bucketTimeSec, percent); +} + void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, String8& result) const { @@ -2647,6 +2707,11 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY)); result.append("\n"); + // Dump static screen stats + result.append("\n"); + dumpStaticScreenStats(result); + result.append("\n"); + /* * Dump the visible layer list */ @@ -2794,7 +2859,7 @@ status_t SurfaceFlinger::onTransact( IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS) && + if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) && !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { ALOGE("Permission Denial: " "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); @@ -3253,8 +3318,12 @@ status_t SurfaceFlinger::captureScreenImplLocked( ATRACE_CALL(); // get screen geometry - const uint32_t hw_w = hw->getWidth(); - const uint32_t hw_h = hw->getHeight(); + uint32_t hw_w = hw->getWidth(); + uint32_t hw_h = hw->getHeight(); + + if (rotation & Transform::ROT_90) { + std::swap(hw_w, hw_h); + } if ((reqWidth > hw_w) || (reqHeight > hw_h)) { ALOGE("size mismatch (%d, %d) > (%d, %d)", @@ -3270,8 +3339,8 @@ status_t SurfaceFlinger::captureScreenImplLocked( sp<Surface> sur = new Surface(producer, false); ANativeWindow* window = sur.get(); - status_t result = NO_ERROR; - if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) == NO_ERROR) { + status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); + if (result == NO_ERROR) { uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; @@ -3361,7 +3430,7 @@ status_t SurfaceFlinger::captureScreenImplLocked( result = BAD_VALUE; } // queueBuffer takes ownership of syncFd - window->queueBuffer(window, buffer, syncFd); + result = window->queueBuffer(window, buffer, syncFd); } } else { result = BAD_VALUE; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a06d1be..3759a92 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -144,6 +144,8 @@ private: // every half hour. enum { LOG_FRAME_STATS_PERIOD = 30*60*60 }; + static const size_t MAX_LAYERS = 4096; + // We're reference counted, never destroy SurfaceFlinger directly virtual ~SurfaceFlinger(); @@ -305,7 +307,7 @@ private: status_t removeLayer(const sp<Layer>& layer); // add a layer to SurfaceFlinger - void addClientLayer(const sp<Client>& client, + status_t addClientLayer(const sp<Client>& client, const sp<IBinder>& handle, const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc); @@ -416,6 +418,8 @@ private: void logFrameStats(); + void dumpStaticScreenStats(String8& result) const; + /* ------------------------------------------------------------------------ * Attributes */ @@ -494,6 +498,13 @@ private: mat4 mColorMatrix; bool mHasColorMatrix; + + // Static screen stats + bool mHasPoweredOff; + static const size_t NUM_BUCKETS = 8; // < 1-7, 7+ + nsecs_t mFrameBuckets[NUM_BUCKETS]; + nsecs_t mTotalTime; + nsecs_t mLastSwapTime; }; }; // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index 19c497a..ed1f31b 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -32,7 +32,7 @@ namespace android { // --------------------------------------------------------------------------- status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, - const DispSync& dispSync) + const DispSync& dispSync, uint64_t maxFrameNumber) { ATRACE_CALL(); ALOGV("updateTexImage"); @@ -54,7 +54,8 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, // 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, computeExpectedPresent(dispSync)); + err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), + maxFrameNumber); if (err != NO_ERROR) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { err = NO_ERROR; @@ -74,7 +75,7 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, int buf = item.mBuf; if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) { releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR); - return NO_ERROR; + return BUFFER_REJECTED; } // Release the previous buffer. @@ -104,8 +105,9 @@ status_t SurfaceFlingerConsumer::bindTextureImage() } status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item, - nsecs_t presentWhen) { - status_t result = GLConsumer::acquireBufferLocked(item, presentWhen); + nsecs_t presentWhen, uint64_t maxFrameNumber) { + status_t result = GLConsumer::acquireBufferLocked(item, presentWhen, + maxFrameNumber); if (result == NO_ERROR) { mTransformToDisplayInverse = item->mTransformToDisplayInverse; mSurfaceDamage = item->mSurfaceDamage; diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h index 1aaba18..779e5b7 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.h +++ b/services/surfaceflinger/SurfaceFlingerConsumer.h @@ -28,6 +28,8 @@ namespace android { */ class SurfaceFlingerConsumer : public GLConsumer { public: + static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8; + struct ContentsChangedListener: public FrameAvailableListener { virtual void onSidebandStreamChanged() = 0; }; @@ -47,13 +49,15 @@ public: virtual ~BufferRejecter() { } }; - virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen); + virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, + uint64_t maxFrameNumber = 0) override; // This version of updateTexImage() takes a functor that may be used to // reject the newly acquired buffer. Unlike the GLConsumer version, // this does not guarantee that the buffer has been bound to the GL // texture. - status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync); + status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, + uint64_t maxFrameNumber = 0); // See GLConsumer::bindTextureImageLocked(). status_t bindTextureImage(); diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index 4d363c8..dcde512 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -16,6 +16,8 @@ #include <gtest/gtest.h> +#include <android/native_window.h> + #include <binder/IMemory.h> #include <gui/ISurfaceComposer.h> @@ -53,21 +55,23 @@ static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, class ScreenCapture : public RefBase { public: static void captureScreen(sp<ScreenCapture>* sc) { - sp<IMemoryHeap> heap; - uint32_t w=0, h=0; - PixelFormat fmt=0; + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + IGraphicBufferProducer::QueueBufferOutput bufferOutput; + sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1); sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt, 0, 0, - 0, INT_MAX)); - ASSERT_TRUE(heap != NULL); - ASSERT_EQ(PIXEL_FORMAT_RGBA_8888, fmt); - *sc = new ScreenCapture(w, h, heap); + sp<IBinder> display(sf->getBuiltInDisplay( + ISurfaceComposer::eDisplayIdMain)); + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 0, 0, + 0, INT_MAX, false)); + *sc = new ScreenCapture(cpuConsumer); } void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) { - const uint8_t* img = reinterpret_cast<const uint8_t*>(mHeap->base()); - const uint8_t* pixel = img + (4 * (y*mWidth + x)); + ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mBuf.format); + const uint8_t* img = static_cast<const uint8_t*>(mBuf.data); + const uint8_t* pixel = img + (4 * (y * mBuf.stride + x)); if (r != pixel[0] || g != pixel[1] || b != pixel[2]) { String8 err(String8::format("pixel @ (%3d, %3d): " "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", @@ -77,15 +81,17 @@ public: } private: - ScreenCapture(uint32_t w, uint32_t h, const sp<IMemoryHeap>& heap) : - mWidth(w), - mHeight(h), - mHeap(heap) - {} - - const uint32_t mWidth; - const uint32_t mHeight; - sp<IMemoryHeap> mHeap; + ScreenCapture(const sp<CpuConsumer>& cc) : + mCC(cc) { + EXPECT_EQ(NO_ERROR, mCC->lockNextBuffer(&mBuf)); + } + + ~ScreenCapture() { + mCC->unlockBuffer(mBuf); + } + + sp<CpuConsumer> mCC; + CpuConsumer::LockedBuffer mBuf; }; class LayerUpdateTest : public ::testing::Test { |