diff options
author | 2016-10-11 00:15:18 +0000 | |
---|---|---|
committer | 2016-10-11 00:15:18 +0000 | |
commit | 9d96de49673cb6c916bfb797aad4f4e024ea73ca (patch) | |
tree | 99fc88f0e10e7764cd1a5ddf03189c2379dfbbd3 | |
parent | 90f923493fa053655a203c34ea491086aeb07602 (diff) |
Revert "Delete HWC1"
This reverts commit 90f923493fa053655a203c34ea491086aeb07602.
Change-Id: If9da49e3bc85f8ff21ac1bd22a6bab97e9aa3103
26 files changed, 6175 insertions, 2 deletions
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index f008099a2f..39b4528087 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -17,14 +17,12 @@ LOCAL_SRC_FILES := \ LayerDim.cpp \ MessageQueue.cpp \ MonitoredProducer.cpp \ - SurfaceFlinger.cpp \ SurfaceFlingerConsumer.cpp \ SurfaceInterceptor.cpp \ Transform.cpp \ DisplayHardware/FramebufferSurface.cpp \ DisplayHardware/HWC2.cpp \ DisplayHardware/HWC2On1Adapter.cpp \ - DisplayHardware/HWComposer.cpp \ DisplayHardware/PowerHAL.cpp \ DisplayHardware/VirtualDisplaySurface.cpp \ Effects/Daltonizer.cpp \ @@ -49,6 +47,17 @@ LOCAL_C_INCLUDES := \ LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES +ifeq ($(TARGET_USES_HWC2),true) + LOCAL_CFLAGS += -DUSE_HWC2 + LOCAL_SRC_FILES += \ + SurfaceFlinger.cpp \ + DisplayHardware/HWComposer.cpp +else + LOCAL_SRC_FILES += \ + SurfaceFlinger_hwc1.cpp \ + DisplayHardware/HWComposer_hwc1.cpp +endif + ifeq ($(TARGET_BOARD_PLATFORM),omap4) LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY endif @@ -157,6 +166,10 @@ ifneq ($(ENABLE_CPUSETS),) LOCAL_CFLAGS += -DENABLE_CPUSETS endif +ifeq ($(TARGET_USES_HWC2),true) + LOCAL_CFLAGS += -DUSE_HWC2 +endif + LOCAL_SRC_FILES := \ main_surfaceflinger.cpp diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 43fb19dc07..6c18ef7389 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -37,7 +37,9 @@ #include "DisplayHardware/DisplaySurface.h" #include "DisplayHardware/HWComposer.h" +#ifdef USE_HWC2 #include "DisplayHardware/HWC2.h" +#endif #include "RenderEngine/RenderEngine.h" #include "clz.h" @@ -72,6 +74,9 @@ DisplayDevice::DisplayDevice( const sp<SurfaceFlinger>& flinger, DisplayType type, int32_t hwcId, +#ifndef USE_HWC2 + int format, +#endif bool isSecure, const wp<IBinder>& displayToken, const sp<DisplaySurface>& displaySurface, @@ -87,6 +92,9 @@ DisplayDevice::DisplayDevice( mSurface(EGL_NO_SURFACE), mDisplayWidth(), mDisplayHeight(), +#ifndef USE_HWC2 + mFormat(), +#endif mFlags(), mPageFlipCount(), mIsSecure(isSecure), @@ -106,7 +114,11 @@ DisplayDevice::DisplayDevice( EGLSurface eglSurface; EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (config == EGL_NO_CONFIG) { +#ifdef USE_HWC2 config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888); +#else + config = RenderEngine::chooseEglConfig(display, format); +#endif } eglSurface = eglCreateWindowSurface(display, config, window, NULL); eglQuerySurface(display, eglSurface, EGL_WIDTH, &mDisplayWidth); @@ -125,6 +137,9 @@ DisplayDevice::DisplayDevice( mConfig = config; mDisplay = display; mSurface = eglSurface; +#ifndef USE_HWC2 + mFormat = format; +#endif mPageFlipCount = 0; mViewport.makeInvalid(); mFrame.makeInvalid(); @@ -165,6 +180,10 @@ DisplayDevice::~DisplayDevice() { void DisplayDevice::disconnect(HWComposer& hwc) { if (mHwcDisplayId >= 0) { hwc.disconnectDisplay(mHwcDisplayId); +#ifndef USE_HWC2 + if (mHwcDisplayId >= DISPLAY_VIRTUAL) + hwc.freeDisplayId(mHwcDisplayId); +#endif mHwcDisplayId = -1; } } @@ -181,6 +200,12 @@ int DisplayDevice::getHeight() const { return mDisplayHeight; } +#ifndef USE_HWC2 +PixelFormat DisplayDevice::getFormat() const { + return mFormat; +} +#endif + EGLSurface DisplayDevice::getEGLSurface() const { return mSurface; } @@ -196,6 +221,12 @@ uint32_t DisplayDevice::getPageFlipCount() const { return mPageFlipCount; } +#ifndef USE_HWC2 +status_t DisplayDevice::compositionComplete() const { + return mDisplaySurface->compositionComplete(); +} +#endif + void DisplayDevice::flip(const Region& dirty) const { mFlinger->getRenderEngine().checkErrors(); @@ -216,6 +247,7 @@ status_t DisplayDevice::beginFrame(bool mustRecompose) const { return mDisplaySurface->beginFrame(mustRecompose); } +#ifdef USE_HWC2 status_t DisplayDevice::prepareFrame(HWComposer& hwc) { status_t error = hwc.prepare(*this); if (error != NO_ERROR) { @@ -239,9 +271,41 @@ status_t DisplayDevice::prepareFrame(HWComposer& hwc) { } return mDisplaySurface->prepareFrame(compositionType); } +#else +status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const { + DisplaySurface::CompositionType compositionType; + bool haveGles = hwc.hasGlesComposition(mHwcDisplayId); + bool haveHwc = hwc.hasHwcComposition(mHwcDisplayId); + if (haveGles && haveHwc) { + compositionType = DisplaySurface::COMPOSITION_MIXED; + } else if (haveGles) { + compositionType = DisplaySurface::COMPOSITION_GLES; + } else if (haveHwc) { + compositionType = DisplaySurface::COMPOSITION_HWC; + } else { + // Nothing to do -- when turning the screen off we get a frame like + // this. Call it a HWC frame since we won't be doing any GLES work but + // will do a prepare/set cycle. + compositionType = DisplaySurface::COMPOSITION_HWC; + } + return mDisplaySurface->prepareFrame(compositionType); +} +#endif void DisplayDevice::swapBuffers(HWComposer& hwc) const { +#ifdef USE_HWC2 if (hwc.hasClientComposition(mHwcDisplayId)) { +#else + // We need to call eglSwapBuffers() if: + // (1) we don't have a hardware composer, or + // (2) we did GLES composition this frame, and either + // (a) we have framebuffer target support (not present on legacy + // devices, where HWComposer::commit() handles things); or + // (b) this is a virtual display + if (hwc.initCheck() != NO_ERROR || + (hwc.hasGlesComposition(mHwcDisplayId) && + (hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) { +#endif EGLBoolean success = eglSwapBuffers(mDisplay, mSurface); if (!success) { EGLint error = eglGetError(); @@ -263,9 +327,17 @@ void DisplayDevice::swapBuffers(HWComposer& hwc) const { } } +#ifdef USE_HWC2 void DisplayDevice::onSwapBuffersCompleted() const { mDisplaySurface->onFrameCommitted(); } +#else +void DisplayDevice::onSwapBuffersCompleted(HWComposer& hwc) const { + if (hwc.initCheck() == NO_ERROR) { + mDisplaySurface->onFrameCommitted(); + } +} +#endif uint32_t DisplayDevice::getFlags() const { @@ -343,6 +415,7 @@ int DisplayDevice::getActiveConfig() const { } // ---------------------------------------------------------------------------- +#ifdef USE_HWC2 void DisplayDevice::setActiveColorMode(android_color_mode_t mode) { mActiveColorMode = mode; } @@ -350,6 +423,7 @@ void DisplayDevice::setActiveColorMode(android_color_mode_t mode) { android_color_mode_t DisplayDevice::getActiveColorMode() const { return mActiveColorMode; } +#endif // ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 7e8f156fea..92ede08f74 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -21,20 +21,27 @@ #include <stdlib.h> +#ifndef USE_HWC2 +#include <ui/PixelFormat.h> +#endif #include <ui/Region.h> #include <EGL/egl.h> #include <EGL/eglext.h> +#ifdef USE_HWC2 #include <binder/IBinder.h> #include <utils/RefBase.h> +#endif #include <utils/Mutex.h> #include <utils/String8.h> #include <utils/Timers.h> #include <hardware/hwcomposer_defs.h> +#ifdef USE_HWC2 #include <memory> +#endif struct ANativeWindow; @@ -80,6 +87,9 @@ public: const sp<SurfaceFlinger>& flinger, DisplayType type, int32_t hwcId, +#ifndef USE_HWC2 + int format, +#endif bool isSecure, const wp<IBinder>& displayToken, const sp<DisplaySurface>& displaySurface, @@ -102,6 +112,9 @@ public: int getWidth() const; int getHeight() const; +#ifndef USE_HWC2 + PixelFormat getFormat() const; +#endif uint32_t getFlags() const; EGLSurface getEGLSurface() const; @@ -131,12 +144,23 @@ public: // We pass in mustRecompose so we can keep VirtualDisplaySurface's state // machine happy without actually queueing a buffer if nothing has changed status_t beginFrame(bool mustRecompose) const; +#ifdef USE_HWC2 status_t prepareFrame(HWComposer& hwc); +#else + status_t prepareFrame(const HWComposer& hwc) const; +#endif void swapBuffers(HWComposer& hwc) const; +#ifndef USE_HWC2 + status_t compositionComplete() const; +#endif // called after h/w composer has completed its set() call +#ifdef USE_HWC2 void onSwapBuffersCompleted() const; +#else + void onSwapBuffersCompleted(HWComposer& hwc) const; +#endif Rect getBounds() const { return Rect(mDisplayWidth, mDisplayHeight); @@ -158,8 +182,10 @@ public: void setPowerMode(int mode); bool isDisplayOn() const; +#ifdef USE_HWC2 android_color_mode_t getActiveColorMode() const; void setActiveColorMode(android_color_mode_t mode); +#endif /* ------------------------------------------------------------------------ * Display active config management. @@ -194,6 +220,9 @@ private: EGLSurface mSurface; int mDisplayWidth; int mDisplayHeight; +#ifndef USE_HWC2 + PixelFormat mFormat; +#endif uint32_t mFlags; mutable uint32_t mPageFlipCount; String8 mDisplayName; @@ -228,8 +257,10 @@ private: int mPowerMode; // Current active config int mActiveConfig; +#ifdef USE_HWC2 // current active color mode android_color_mode_t mActiveColorMode; +#endif }; struct DisplayDeviceState { diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h index d39a3aab19..d801bb3a98 100644 --- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h @@ -49,6 +49,14 @@ public: }; virtual status_t prepareFrame(CompositionType compositionType) = 0; +#ifndef USE_HWC2 + // Should be called when composition rendering is complete for a frame (but + // eglSwapBuffers hasn't necessarily been called). Required by certain + // older drivers for synchronization. + // TODO: Remove this when we drop support for HWC 1.0. + virtual status_t compositionComplete() = 0; +#endif + // Inform the surface that GLES composition is complete for this frame, and // the surface should make sure that HWComposer has the correct buffer for // this frame. Some implementations may only push a new buffer to diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index a50b5503d2..18c7945577 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -62,20 +62,32 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp, mCurrentBufferSlot(-1), mCurrentBuffer(), mCurrentFence(Fence::NO_FENCE), +#ifdef USE_HWC2 mHwc(hwc), mHasPendingRelease(false), mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT), mPreviousBuffer() +#else + mHwc(hwc) +#endif { +#ifdef USE_HWC2 ALOGV("Creating for display %d", disp); +#endif + mName = "FramebufferSurface"; mConsumer->setConsumerName(mName); mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER); +#ifdef USE_HWC2 const auto& activeConfig = mHwc.getActiveConfig(disp); mConsumer->setDefaultBufferSize(activeConfig->getWidth(), activeConfig->getHeight()); +#else + mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp)); + mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp)); +#endif mConsumer->setMaxAcquiredBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS - 1); } @@ -88,6 +100,7 @@ status_t FramebufferSurface::prepareFrame(CompositionType /*compositionType*/) { } status_t FramebufferSurface::advanceFrame() { +#ifdef USE_HWC2 sp<GraphicBuffer> buf; sp<Fence> acquireFence(Fence::NO_FENCE); android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN; @@ -102,10 +115,20 @@ status_t FramebufferSurface::advanceFrame() { ALOGE("error posting framebuffer: %d", result); } return result; +#else + // Once we remove FB HAL support, we can call nextBuffer() from here + // instead of using onFrameAvailable(). No real benefit, except it'll be + // more like VirtualDisplaySurface. + return NO_ERROR; +#endif } +#ifdef USE_HWC2 status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence, android_dataspace_t& outDataspace) { +#else +status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence) { +#endif Mutex::Autolock lock(mMutex); BufferItem item; @@ -128,9 +151,19 @@ status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, // had released the old buffer first. if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT && item.mSlot != mCurrentBufferSlot) { +#ifdef USE_HWC2 mHasPendingRelease = true; mPreviousBufferSlot = mCurrentBufferSlot; mPreviousBuffer = mCurrentBuffer; +#else + // Release the previous buffer. + err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); + if (err < NO_ERROR) { + ALOGE("error releasing buffer: %s (%d)", strerror(-err), err); + return err; + } +#endif } mCurrentBufferSlot = item.mSlot; mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer; @@ -138,10 +171,30 @@ status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, outFence = item.mFence; outBuffer = mCurrentBuffer; +#ifdef USE_HWC2 outDataspace = item.mDataSpace; +#endif return NO_ERROR; } +#ifndef USE_HWC2 +// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl. +void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) { + sp<GraphicBuffer> buf; + sp<Fence> acquireFence; + status_t err = nextBuffer(buf, acquireFence); + if (err != NO_ERROR) { + ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)", + strerror(-err), err); + return; + } + err = mHwc.fbPost(mDisplayType, acquireFence, buf); + if (err != NO_ERROR) { + ALOGE("error posting framebuffer: %d", err); + } +} +#endif + void FramebufferSurface::freeBufferLocked(int slotIndex) { ConsumerBase::freeBufferLocked(slotIndex); if (slotIndex == mCurrentBufferSlot) { @@ -150,6 +203,7 @@ void FramebufferSurface::freeBufferLocked(int slotIndex) { } void FramebufferSurface::onFrameCommitted() { +#ifdef USE_HWC2 if (mHasPendingRelease) { sp<Fence> fence = mHwc.getRetireFence(mDisplayType); if (fence->isValid()) { @@ -166,14 +220,34 @@ void FramebufferSurface::onFrameCommitted() { mPreviousBuffer.clear(); mHasPendingRelease = false; } +#else + sp<Fence> fence = mHwc.getAndResetReleaseFence(mDisplayType); + if (fence->isValid() && + mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) { + status_t err = addReleaseFence(mCurrentBufferSlot, + mCurrentBuffer, fence); + ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)", + strerror(-err), err); + } +#endif } +#ifndef USE_HWC2 +status_t FramebufferSurface::compositionComplete() +{ + return mHwc.fbCompositionComplete(); +} +#endif + void FramebufferSurface::dumpAsString(String8& result) const { ConsumerBase::dumpState(result); } void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const { +#ifndef USE_HWC2 + mHwc.fbDump(result); +#endif ConsumerBase::dumpLocked(result, prefix); } diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index eb70479d29..439435ac50 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -41,6 +41,9 @@ public: virtual status_t beginFrame(bool mustRecompose); virtual status_t prepareFrame(CompositionType compositionType); +#ifndef USE_HWC2 + virtual status_t compositionComplete(); +#endif virtual status_t advanceFrame(); virtual void onFrameCommitted(); virtual void dumpAsString(String8& result) const; @@ -54,6 +57,9 @@ public: private: virtual ~FramebufferSurface() { }; // this class cannot be overloaded +#ifndef USE_HWC2 + virtual void onFrameAvailable(const BufferItem& item); +#endif virtual void freeBufferLocked(int slotIndex); virtual void dumpLocked(String8& result, const char* prefix) const; @@ -61,8 +67,12 @@ private: // nextBuffer waits for and then latches the next buffer from the // BufferQueue and releases the previously latched buffer to the // BufferQueue. The new buffer is returned in the 'buffer' argument. +#ifdef USE_HWC2 status_t nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence, android_dataspace_t& outDataspace); +#else + status_t nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence); +#endif // mDisplayType must match one of the HWC display types int mDisplayType; @@ -82,10 +92,12 @@ private: // Hardware composer, owned by SurfaceFlinger. HWComposer& mHwc; +#ifdef USE_HWC2 // Previous buffer to release after getting an updated retire fence bool mHasPendingRelease; int mPreviousBufferSlot; sp<GraphicBuffer> mPreviousBuffer; +#endif }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index b25f5adf25..41671f62fd 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -14,6 +14,10 @@ * limitations under the License. */ +#ifndef USE_HWC2 +#include "HWComposer_hwc1.h" +#else + #ifndef ANDROID_SF_HWCOMPOSER_H #define ANDROID_SF_HWCOMPOSER_H @@ -220,3 +224,5 @@ private: }; // namespace android #endif // ANDROID_SF_HWCOMPOSER_H + +#endif // #ifdef USE_HWC2 diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp new file mode 100644 index 0000000000..2102457994 --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp @@ -0,0 +1,1344 @@ +/* + * Copyright (C) 2010 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 <inttypes.h> +#include <math.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/misc.h> +#include <utils/NativeHandle.h> +#include <utils/String8.h> +#include <utils/Thread.h> +#include <utils/Trace.h> +#include <utils/Vector.h> + +#include <ui/GraphicBuffer.h> + +#include <hardware/hardware.h> +#include <hardware/hwcomposer.h> + +#include <android/configuration.h> + +#include <cutils/log.h> +#include <cutils/properties.h> + +#include <system/graphics.h> + +#include "HWComposer.h" + +#include "../Layer.h" // needed only for debugging +#include "../SurfaceFlinger.h" + +namespace android { + +#define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION + +static uint32_t hwcApiVersion(const hwc_composer_device_1_t* hwc) { + uint32_t hwcVersion = hwc->common.version; + return hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK; +} + +static uint32_t hwcHeaderVersion(const hwc_composer_device_1_t* hwc) { + uint32_t hwcVersion = hwc->common.version; + return hwcVersion & HARDWARE_API_VERSION_2_HEADER_MASK; +} + +static bool hwcHasApiVersion(const hwc_composer_device_1_t* hwc, + uint32_t version) { + return hwcApiVersion(hwc) >= (version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK); +} + +// --------------------------------------------------------------------------- + +struct HWComposer::cb_context { + struct callbacks : public hwc_procs_t { + // these are here to facilitate the transition when adding + // new callbacks (an implementation can check for NULL before + // calling a new callback). + void (*zero[4])(void); + }; + callbacks procs; + HWComposer* hwc; +}; + +// --------------------------------------------------------------------------- + +HWComposer::HWComposer( + const sp<SurfaceFlinger>& flinger, + EventHandler& handler) + : mFlinger(flinger), + mFbDev(0), mHwc(0), mNumDisplays(1), + mCBContext(new cb_context), + mEventHandler(handler), + mDebugForceFakeVSync(false) +{ + for (size_t i =0 ; i<MAX_HWC_DISPLAYS ; i++) { + mLists[i] = 0; + } + + for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) { + mLastHwVSync[i] = 0; + mVSyncCounts[i] = 0; + } + + char value[PROPERTY_VALUE_MAX]; + property_get("debug.sf.no_hw_vsync", value, "0"); + mDebugForceFakeVSync = atoi(value); + + bool needVSyncThread = true; + + // Note: some devices may insist that the FB HAL be opened before HWC. + int fberr = loadFbHalModule(); + loadHwcModule(); + + if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // close FB HAL if we don't needed it. + // FIXME: this is temporary until we're not forced to open FB HAL + // before HWC. + framebuffer_close(mFbDev); + mFbDev = NULL; + } + + // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory. + if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) + && !mFbDev) { + ALOGE("ERROR: failed to open framebuffer (%s), aborting", + strerror(-fberr)); + abort(); + } + + // these display IDs are always reserved + for (size_t i=0 ; i<NUM_BUILTIN_DISPLAYS ; i++) { + mAllocatedDisplayIDs.markBit(i); + } + + if (mHwc) { + ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER, + (hwcApiVersion(mHwc) >> 24) & 0xff, + (hwcApiVersion(mHwc) >> 16) & 0xff); + if (mHwc->registerProcs) { + mCBContext->hwc = this; + mCBContext->procs.invalidate = &hook_invalidate; + mCBContext->procs.vsync = &hook_vsync; + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) + mCBContext->procs.hotplug = &hook_hotplug; + else + mCBContext->procs.hotplug = NULL; + memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero)); + mHwc->registerProcs(mHwc, &mCBContext->procs); + } + + // don't need a vsync thread if we have a hardware composer + needVSyncThread = false; + // always turn vsync off when we start + eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0); + + // the number of displays we actually have depends on the + // hw composer version + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { + // 1.3 adds support for virtual displays + mNumDisplays = MAX_HWC_DISPLAYS; + } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // 1.1 adds support for multiple displays + mNumDisplays = NUM_BUILTIN_DISPLAYS; + } else { + mNumDisplays = 1; + } + } + + if (mFbDev) { + ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)), + "should only have fbdev if no hwc or hwc is 1.0"); + + DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]); + disp.connected = true; + disp.format = mFbDev->format; + DisplayConfig config = DisplayConfig(); + config.width = mFbDev->width; + config.height = mFbDev->height; + config.xdpi = mFbDev->xdpi; + config.ydpi = mFbDev->ydpi; + config.refresh = nsecs_t(1e9 / mFbDev->fps); + disp.configs.push_back(config); + disp.currentConfig = 0; + } else if (mHwc) { + // here we're guaranteed to have at least HWC 1.1 + for (size_t i =0 ; i<NUM_BUILTIN_DISPLAYS ; i++) { + queryDisplayProperties(i); + } + } + + if (needVSyncThread) { + // we don't have VSYNC support, we need to fake it + mVSyncThread = new VSyncThread(*this); + } +} + +HWComposer::~HWComposer() { + if (mHwc) { + eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0); + } + if (mVSyncThread != NULL) { + mVSyncThread->requestExitAndWait(); + } + if (mHwc) { + hwc_close_1(mHwc); + } + if (mFbDev) { + framebuffer_close(mFbDev); + } + delete mCBContext; +} + +// Load and prepare the hardware composer module. Sets mHwc. +void HWComposer::loadHwcModule() +{ + hw_module_t const* module; + + if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) { + ALOGE("%s module not found", HWC_HARDWARE_MODULE_ID); + return; + } + + int err = hwc_open_1(module, &mHwc); + if (err) { + ALOGE("%s device failed to initialize (%s)", + HWC_HARDWARE_COMPOSER, strerror(-err)); + return; + } + + if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) || + hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION || + hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) { + ALOGE("%s device version %#x unsupported, will not be used", + HWC_HARDWARE_COMPOSER, mHwc->common.version); + hwc_close_1(mHwc); + mHwc = NULL; + return; + } +} + +// Load and prepare the FB HAL, which uses the gralloc module. Sets mFbDev. +int HWComposer::loadFbHalModule() +{ + hw_module_t const* module; + + int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); + if (err != 0) { + ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID); + return err; + } + + return framebuffer_open(module, &mFbDev); +} + +status_t HWComposer::initCheck() const { + return mHwc ? NO_ERROR : NO_INIT; +} + +void HWComposer::hook_invalidate(const struct hwc_procs* procs) { + cb_context* ctx = reinterpret_cast<cb_context*>( + const_cast<hwc_procs_t*>(procs)); + ctx->hwc->invalidate(); +} + +void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp, + int64_t timestamp) { + cb_context* ctx = reinterpret_cast<cb_context*>( + const_cast<hwc_procs_t*>(procs)); + ctx->hwc->vsync(disp, timestamp); +} + +void HWComposer::hook_hotplug(const struct hwc_procs* procs, int disp, + int connected) { + cb_context* ctx = reinterpret_cast<cb_context*>( + const_cast<hwc_procs_t*>(procs)); + ctx->hwc->hotplug(disp, connected); +} + +void HWComposer::invalidate() { + mFlinger->repaintEverything(); +} + +void HWComposer::vsync(int disp, int64_t timestamp) { + if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) { + { + Mutex::Autolock _l(mLock); + + // There have been reports of HWCs that signal several vsync events + // with the same timestamp when turning the display off and on. This + // is a bug in the HWC implementation, but filter the extra events + // out here so they don't cause havoc downstream. + if (timestamp == mLastHwVSync[disp]) { + ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")", + timestamp); + return; + } + + mLastHwVSync[disp] = timestamp; + } + + char tag[16]; + snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp); + ATRACE_INT(tag, ++mVSyncCounts[disp] & 1); + + mEventHandler.onVSyncReceived(disp, timestamp); + } +} + +void HWComposer::hotplug(int disp, int connected) { + if (disp >= VIRTUAL_DISPLAY_ID_BASE) { + ALOGE("hotplug event received for invalid display: disp=%d connected=%d", + disp, connected); + return; + } + queryDisplayProperties(disp); + // 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) { + // Default density is based on TVs: 1080p displays get XHIGH density, + // lower-resolution displays get TV density. Maybe eventually we'll need + // to update it for 4K displays, though hopefully those just report + // accurate DPI information to begin with. This is also used for virtual + // displays and even primary displays with older hwcomposers, so be + // careful about orientation. + + uint32_t h = width < height ? width : height; + if (h >= 1080) return ACONFIGURATION_DENSITY_XHIGH; + else return ACONFIGURATION_DENSITY_TV; +} + +static const uint32_t DISPLAY_ATTRIBUTES[] = { + HWC_DISPLAY_VSYNC_PERIOD, + HWC_DISPLAY_WIDTH, + HWC_DISPLAY_HEIGHT, + HWC_DISPLAY_DPI_X, + HWC_DISPLAY_DPI_Y, + HWC_DISPLAY_COLOR_TRANSFORM, + HWC_DISPLAY_NO_ATTRIBUTE, +}; +#define NUM_DISPLAY_ATTRIBUTES (sizeof(DISPLAY_ATTRIBUTES) / sizeof(DISPLAY_ATTRIBUTES)[0]) + +static const uint32_t PRE_HWC15_DISPLAY_ATTRIBUTES[] = { + HWC_DISPLAY_VSYNC_PERIOD, + HWC_DISPLAY_WIDTH, + HWC_DISPLAY_HEIGHT, + HWC_DISPLAY_DPI_X, + HWC_DISPLAY_DPI_Y, + HWC_DISPLAY_NO_ATTRIBUTE, +}; + +status_t HWComposer::queryDisplayProperties(int disp) { + + LOG_ALWAYS_FATAL_IF(!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)); + + // use zero as default value for unspecified attributes + int32_t values[NUM_DISPLAY_ATTRIBUTES - 1]; + memset(values, 0, sizeof(values)); + + const size_t MAX_NUM_CONFIGS = 128; + uint32_t configs[MAX_NUM_CONFIGS] = {0}; + size_t numConfigs = MAX_NUM_CONFIGS; + status_t err = mHwc->getDisplayConfigs(mHwc, disp, configs, &numConfigs); + if (err != NO_ERROR) { + // this can happen if an unpluggable display is not connected + mDisplayData[disp].connected = false; + return err; + } + + mDisplayData[disp].currentConfig = 0; + for (size_t c = 0; c < numConfigs; ++c) { + err = mHwc->getDisplayAttributes(mHwc, disp, configs[c], + DISPLAY_ATTRIBUTES, values); + // If this is a pre-1.5 HWC, it may not know about color transform, so + // try again with a smaller set of attributes + if (err != NO_ERROR) { + err = mHwc->getDisplayAttributes(mHwc, disp, configs[c], + PRE_HWC15_DISPLAY_ATTRIBUTES, values); + } + if (err != NO_ERROR) { + // we can't get this display's info. turn it off. + mDisplayData[disp].connected = false; + return err; + } + + DisplayConfig config = DisplayConfig(); + for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) { + switch (DISPLAY_ATTRIBUTES[i]) { + case HWC_DISPLAY_VSYNC_PERIOD: + config.refresh = nsecs_t(values[i]); + break; + case HWC_DISPLAY_WIDTH: + config.width = values[i]; + break; + case HWC_DISPLAY_HEIGHT: + config.height = values[i]; + break; + case HWC_DISPLAY_DPI_X: + config.xdpi = values[i] / 1000.0f; + break; + case HWC_DISPLAY_DPI_Y: + config.ydpi = values[i] / 1000.0f; + break; + case HWC_DISPLAY_COLOR_TRANSFORM: + config.colorMode = static_cast<android_color_mode_t>(values[i]); + break; + default: + ALOG_ASSERT(false, "unknown display attribute[%zu] %#x", + i, DISPLAY_ATTRIBUTES[i]); + break; + } + } + + if (config.xdpi == 0.0f || config.ydpi == 0.0f) { + float dpi = getDefaultDensity(config.width, config.height); + config.xdpi = dpi; + config.ydpi = dpi; + } + + mDisplayData[disp].configs.push_back(config); + } + + // FIXME: what should we set the format to? + mDisplayData[disp].format = HAL_PIXEL_FORMAT_RGBA_8888; + mDisplayData[disp].connected = true; + return NO_ERROR; +} + +status_t HWComposer::setVirtualDisplayProperties(int32_t id, + uint32_t w, uint32_t h, uint32_t format) { + if (id < VIRTUAL_DISPLAY_ID_BASE || id >= int32_t(mNumDisplays) || + !mAllocatedDisplayIDs.hasBit(id)) { + return BAD_INDEX; + } + size_t configId = mDisplayData[id].currentConfig; + mDisplayData[id].format = format; + DisplayConfig& config = mDisplayData[id].configs.editItemAt(configId); + config.width = w; + config.height = h; + config.xdpi = config.ydpi = getDefaultDensity(w, h); + return NO_ERROR; +} + +int32_t HWComposer::allocateDisplayId() { + if (mAllocatedDisplayIDs.count() >= mNumDisplays) { + return NO_MEMORY; + } + int32_t id = mAllocatedDisplayIDs.firstUnmarkedBit(); + mAllocatedDisplayIDs.markBit(id); + mDisplayData[id].connected = true; + mDisplayData[id].configs.resize(1); + mDisplayData[id].currentConfig = 0; + return id; +} + +status_t HWComposer::freeDisplayId(int32_t id) { + if (id < NUM_BUILTIN_DISPLAYS) { + // cannot free the reserved IDs + return BAD_VALUE; + } + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { + return BAD_INDEX; + } + mAllocatedDisplayIDs.clearBit(id); + mDisplayData[id].connected = false; + return NO_ERROR; +} + +nsecs_t HWComposer::getRefreshTimestamp(int disp) const { + // this returns the last refresh timestamp. + // if the last one is not available, we estimate it based on + // the refresh period and whatever closest timestamp we have. + Mutex::Autolock _l(mLock); + nsecs_t now = systemTime(CLOCK_MONOTONIC); + size_t configId = mDisplayData[disp].currentConfig; + return now - ((now - mLastHwVSync[disp]) % + mDisplayData[disp].configs[configId].refresh); +} + +sp<Fence> HWComposer::getDisplayFence(int disp) const { + return mDisplayData[disp].lastDisplayFence; +} + +uint32_t HWComposer::getFormat(int disp) const { + if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) { + return HAL_PIXEL_FORMAT_RGBA_8888; + } else { + return mDisplayData[disp].format; + } +} + +bool HWComposer::isConnected(int disp) const { + return mDisplayData[disp].connected; +} + +uint32_t HWComposer::getWidth(int disp) const { + size_t currentConfig = mDisplayData[disp].currentConfig; + return mDisplayData[disp].configs[currentConfig].width; +} + +uint32_t HWComposer::getHeight(int disp) const { + size_t currentConfig = mDisplayData[disp].currentConfig; + return mDisplayData[disp].configs[currentConfig].height; +} + +float HWComposer::getDpiX(int disp) const { + size_t currentConfig = mDisplayData[disp].currentConfig; + return mDisplayData[disp].configs[currentConfig].xdpi; +} + +float HWComposer::getDpiY(int disp) const { + size_t currentConfig = mDisplayData[disp].currentConfig; + return mDisplayData[disp].configs[currentConfig].ydpi; +} + +nsecs_t HWComposer::getRefreshPeriod(int disp) const { + size_t currentConfig = mDisplayData[disp].currentConfig; + return mDisplayData[disp].configs[currentConfig].refresh; +} + +android_color_mode_t HWComposer::getColorMode(int disp) const { + size_t currentConfig = mDisplayData[disp].currentConfig; + return mDisplayData[disp].configs[currentConfig].colorMode; +} + +const Vector<HWComposer::DisplayConfig>& HWComposer::getConfigs(int disp) const { + return mDisplayData[disp].configs; +} + +size_t HWComposer::getCurrentConfig(int disp) const { + return mDisplayData[disp].currentConfig; +} + +void HWComposer::eventControl(int disp, int event, int enabled) { + if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) { + ALOGD("eventControl ignoring event %d on unallocated disp %d (en=%d)", + event, disp, enabled); + return; + } + if (event != EVENT_VSYNC) { + ALOGW("eventControl got unexpected event %d (disp=%d en=%d)", + event, disp, enabled); + return; + } + status_t err = NO_ERROR; + if (mHwc && !mDebugForceFakeVSync) { + // NOTE: we use our own internal lock here because we have to call + // into the HWC with the lock held, and we want to make sure + // that even if HWC blocks (which it shouldn't), it won't + // affect other threads. + Mutex::Autolock _l(mEventControlLock); + const int32_t eventBit = 1UL << event; + const int32_t newValue = enabled ? eventBit : 0; + const int32_t oldValue = mDisplayData[disp].events & eventBit; + if (newValue != oldValue) { + ATRACE_CALL(); + err = mHwc->eventControl(mHwc, disp, event, enabled); + if (!err) { + int32_t& events(mDisplayData[disp].events); + events = (events & ~eventBit) | newValue; + + char tag[16]; + snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", disp); + ATRACE_INT(tag, enabled); + } + } + // error here should not happen -- not sure what we should + // do if it does. + ALOGE_IF(err, "eventControl(%d, %d) failed %s", + event, enabled, strerror(-err)); + } + + if (err == NO_ERROR && mVSyncThread != NULL) { + mVSyncThread->setEnabled(enabled); + } +} + +status_t HWComposer::createWorkList(int32_t id, size_t numLayers) { + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { + return BAD_INDEX; + } + + if (mHwc) { + DisplayData& disp(mDisplayData[id]); + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // we need space for the HWC_FRAMEBUFFER_TARGET + numLayers++; + } + if (disp.capacity < numLayers || disp.list == NULL) { + size_t size = sizeof(hwc_display_contents_1_t) + + numLayers * sizeof(hwc_layer_1_t); + free(disp.list); + disp.list = (hwc_display_contents_1_t*)malloc(size); + disp.capacity = numLayers; + } + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + disp.framebufferTarget = &disp.list->hwLayers[numLayers - 1]; + memset(disp.framebufferTarget, 0, sizeof(hwc_layer_1_t)); + const DisplayConfig& currentConfig = + disp.configs[disp.currentConfig]; + const hwc_rect_t r = { 0, 0, + (int) currentConfig.width, (int) currentConfig.height }; + disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET; + disp.framebufferTarget->hints = 0; + disp.framebufferTarget->flags = 0; + disp.framebufferTarget->handle = disp.fbTargetHandle; + disp.framebufferTarget->transform = 0; + disp.framebufferTarget->blending = HWC_BLENDING_PREMULT; + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { + disp.framebufferTarget->sourceCropf.left = 0; + disp.framebufferTarget->sourceCropf.top = 0; + disp.framebufferTarget->sourceCropf.right = + currentConfig.width; + disp.framebufferTarget->sourceCropf.bottom = + currentConfig.height; + } else { + disp.framebufferTarget->sourceCrop = r; + } + disp.framebufferTarget->displayFrame = r; + disp.framebufferTarget->visibleRegionScreen.numRects = 1; + disp.framebufferTarget->visibleRegionScreen.rects = + &disp.framebufferTarget->displayFrame; + disp.framebufferTarget->acquireFenceFd = -1; + disp.framebufferTarget->releaseFenceFd = -1; + disp.framebufferTarget->planeAlpha = 0xFF; + } + disp.list->retireFenceFd = -1; + disp.list->flags = HWC_GEOMETRY_CHANGED; + disp.list->numHwLayers = numLayers; + } + return NO_ERROR; +} + +status_t HWComposer::setFramebufferTarget(int32_t id, + const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf) { + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { + return BAD_INDEX; + } + DisplayData& disp(mDisplayData[id]); + if (!disp.framebufferTarget) { + // this should never happen, but apparently eglCreateWindowSurface() + // triggers a Surface::queueBuffer() on some + // devices (!?) -- log and ignore. + ALOGE("HWComposer: framebufferTarget is null"); + return NO_ERROR; + } + + int acquireFenceFd = -1; + if (acquireFence->isValid()) { + acquireFenceFd = acquireFence->dup(); + } + + // ALOGD("fbPost: handle=%p, fence=%d", buf->handle, acquireFenceFd); + disp.fbTargetHandle = buf->handle; + disp.framebufferTarget->handle = disp.fbTargetHandle; + disp.framebufferTarget->acquireFenceFd = acquireFenceFd; + return NO_ERROR; +} + +status_t HWComposer::prepare() { + Mutex::Autolock _l(mDisplayLock); + for (size_t i=0 ; i<mNumDisplays ; i++) { + DisplayData& disp(mDisplayData[i]); + if (disp.framebufferTarget) { + // make sure to reset the type to HWC_FRAMEBUFFER_TARGET + // DO NOT reset the handle field to NULL, because it's possible + // that we have nothing to redraw (eg: eglSwapBuffers() not called) + // in which case, we should continue to use the same buffer. + LOG_FATAL_IF(disp.list == NULL); + disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET; + } + if (!disp.connected && disp.list != NULL) { + ALOGW("WARNING: disp %zu: connected, non-null list, layers=%zu", + i, disp.list->numHwLayers); + } + mLists[i] = disp.list; + if (mLists[i]) { + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { + mLists[i]->outbuf = disp.outbufHandle; + mLists[i]->outbufAcquireFenceFd = -1; + } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // garbage data to catch improper use + mLists[i]->dpy = (hwc_display_t)0xDEADBEEF; + mLists[i]->sur = (hwc_surface_t)0xDEADBEEF; + } else { + mLists[i]->dpy = EGL_NO_DISPLAY; + mLists[i]->sur = EGL_NO_SURFACE; + } + } + } + + int err = mHwc->prepare(mHwc, mNumDisplays, mLists); + ALOGE_IF(err, "HWComposer: prepare failed (%s)", strerror(-err)); + + if (err == NO_ERROR) { + // here we're just making sure that "skip" layers are set + // to HWC_FRAMEBUFFER and we're also counting how many layers + // we have of each type. + // + // If there are no window layers, we treat the display has having FB + // composition, because SurfaceFlinger will use GLES to draw the + // wormhole region. + for (size_t i=0 ; i<mNumDisplays ; i++) { + DisplayData& disp(mDisplayData[i]); + disp.hasFbComp = false; + disp.hasOvComp = false; + if (disp.list) { + for (size_t i=0 ; i<disp.list->numHwLayers ; i++) { + hwc_layer_1_t& l = disp.list->hwLayers[i]; + + //ALOGD("prepare: %d, type=%d, handle=%p", + // i, l.compositionType, l.handle); + + if (l.flags & HWC_SKIP_LAYER) { + l.compositionType = HWC_FRAMEBUFFER; + } + if (l.compositionType == HWC_FRAMEBUFFER) { + disp.hasFbComp = true; + } + if (l.compositionType == HWC_OVERLAY) { + disp.hasOvComp = true; + } + if (l.compositionType == HWC_CURSOR_OVERLAY) { + disp.hasOvComp = true; + } + } + if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) { + disp.hasFbComp = true; + } + } else { + disp.hasFbComp = true; + } + } + } + return (status_t)err; +} + +bool HWComposer::hasHwcComposition(int32_t id) const { + if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) + return false; + return mDisplayData[id].hasOvComp; +} + +bool HWComposer::hasGlesComposition(int32_t id) const { + if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) + return true; + return mDisplayData[id].hasFbComp; +} + +sp<Fence> HWComposer::getAndResetReleaseFence(int32_t id) { + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) + return Fence::NO_FENCE; + + int fd = INVALID_OPERATION; + if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + const DisplayData& disp(mDisplayData[id]); + if (disp.framebufferTarget) { + fd = disp.framebufferTarget->releaseFenceFd; + disp.framebufferTarget->acquireFenceFd = -1; + disp.framebufferTarget->releaseFenceFd = -1; + } + } + return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE; +} + +status_t HWComposer::commit() { + int err = NO_ERROR; + if (mHwc) { + if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // On version 1.0, the OpenGL ES target surface is communicated + // by the (dpy, sur) fields and we are guaranteed to have only + // a single display. + mLists[0]->dpy = eglGetCurrentDisplay(); + mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW); + } + + for (size_t i=VIRTUAL_DISPLAY_ID_BASE; i<mNumDisplays; i++) { + DisplayData& disp(mDisplayData[i]); + if (disp.outbufHandle) { + mLists[i]->outbuf = disp.outbufHandle; + mLists[i]->outbufAcquireFenceFd = + disp.outbufAcquireFence->dup(); + } + } + + err = mHwc->set(mHwc, mNumDisplays, mLists); + + for (size_t i=0 ; i<mNumDisplays ; i++) { + DisplayData& disp(mDisplayData[i]); + disp.lastDisplayFence = disp.lastRetireFence; + disp.lastRetireFence = Fence::NO_FENCE; + if (disp.list) { + if (disp.list->retireFenceFd != -1) { + disp.lastRetireFence = new Fence(disp.list->retireFenceFd); + disp.list->retireFenceFd = -1; + } + disp.list->flags &= ~HWC_GEOMETRY_CHANGED; + } + } + } + return (status_t)err; +} + +status_t HWComposer::setPowerMode(int disp, int mode) { + LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE); + if (mHwc) { + if (mode == HWC_POWER_MODE_OFF) { + eventControl(disp, HWC_EVENT_VSYNC, 0); + } + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) { + return (status_t)mHwc->setPowerMode(mHwc, disp, mode); + } else { + return (status_t)mHwc->blank(mHwc, disp, + mode == HWC_POWER_MODE_OFF ? 1 : 0); + } + } + return NO_ERROR; +} + +status_t HWComposer::setActiveConfig(int disp, int mode) { + LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE); + DisplayData& dd(mDisplayData[disp]); + dd.currentConfig = mode; + if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) { + return (status_t)mHwc->setActiveConfig(mHwc, disp, mode); + } else { + LOG_FATAL_IF(mode != 0); + } + return NO_ERROR; +} + +void HWComposer::disconnectDisplay(int disp) { + LOG_ALWAYS_FATAL_IF(disp < 0 || disp == HWC_DISPLAY_PRIMARY); + DisplayData& dd(mDisplayData[disp]); + free(dd.list); + dd.list = NULL; + dd.framebufferTarget = NULL; // points into dd.list + dd.fbTargetHandle = NULL; + dd.outbufHandle = NULL; + dd.lastRetireFence = Fence::NO_FENCE; + dd.lastDisplayFence = Fence::NO_FENCE; + dd.outbufAcquireFence = Fence::NO_FENCE; + // clear all the previous configs and repopulate when a new + // device is added + dd.configs.clear(); +} + +int HWComposer::getVisualID() const { + if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED + // is supported by the implementation. we can only be in this case + // if we have HWC 1.1 + return HAL_PIXEL_FORMAT_RGBA_8888; + //return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; + } else { + return mFbDev->format; + } +} + +bool HWComposer::supportsFramebufferTarget() const { + return (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)); +} + +int HWComposer::fbPost(int32_t id, + const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) { + if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + return setFramebufferTarget(id, acquireFence, buffer); + } else { + acquireFence->waitForever("HWComposer::fbPost"); + return mFbDev->post(mFbDev, buffer->handle); + } +} + +int HWComposer::fbCompositionComplete() { + if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) + return NO_ERROR; + + if (mFbDev->compositionComplete) { + return mFbDev->compositionComplete(mFbDev); + } else { + return INVALID_OPERATION; + } +} + +void HWComposer::fbDump(String8& result) { + if (mFbDev && mFbDev->common.version >= 1 && mFbDev->dump) { + const size_t SIZE = 4096; + char buffer[SIZE]; + mFbDev->dump(mFbDev, buffer, SIZE); + result.append(buffer); + } +} + +status_t HWComposer::setOutputBuffer(int32_t id, const sp<Fence>& acquireFence, + const sp<GraphicBuffer>& buf) { + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) + return BAD_INDEX; + if (id < VIRTUAL_DISPLAY_ID_BASE) + return INVALID_OPERATION; + + DisplayData& disp(mDisplayData[id]); + disp.outbufHandle = buf->handle; + disp.outbufAcquireFence = acquireFence; + return NO_ERROR; +} + +sp<Fence> HWComposer::getLastRetireFence(int32_t id) const { + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) + return Fence::NO_FENCE; + return mDisplayData[id].lastRetireFence; +} + +status_t HWComposer::setCursorPositionAsync(int32_t id, const Rect& pos) +{ + if (mHwc->setCursorPositionAsync) { + return (status_t)mHwc->setCursorPositionAsync(mHwc, id, pos.left, pos.top); + } + else { + return NO_ERROR; + } +} + +/* + * Helper template to implement a concrete HWCLayer + * This holds the pointer to the concrete hwc layer type + * and implements the "iterable" side of HWCLayer. + */ +template<typename CONCRETE, typename HWCTYPE> +class Iterable : public HWComposer::HWCLayer { +protected: + HWCTYPE* const mLayerList; + HWCTYPE* mCurrentLayer; + explicit Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer), + mIndex(0) { } + inline HWCTYPE const * getLayer() const { return mCurrentLayer; } + inline HWCTYPE* getLayer() { return mCurrentLayer; } + virtual ~Iterable() { } + size_t mIndex; +private: + // returns a copy of ourselves + virtual HWComposer::HWCLayer* dup() { + return new CONCRETE( static_cast<const CONCRETE&>(*this) ); + } + virtual status_t setLayer(size_t index) { + mIndex = index; + mCurrentLayer = &mLayerList[index]; + return NO_ERROR; + } +}; + +/* + * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0. + * This implements the HWCLayer side of HWCIterableLayer. + */ +class HWCLayerVersion1 : public Iterable<HWCLayerVersion1, hwc_layer_1_t> { + struct hwc_composer_device_1* mHwc; +public: + HWCLayerVersion1(struct hwc_composer_device_1* hwc, hwc_layer_1_t* layer, + Vector<Region>* visibleRegions, + Vector<Region>* surfaceDamageRegions) + : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer), mHwc(hwc), + mVisibleRegions(visibleRegions), + mSurfaceDamageRegions(surfaceDamageRegions) {} + + virtual int32_t getCompositionType() const { + return getLayer()->compositionType; + } + virtual uint32_t getHints() const { + return getLayer()->hints; + } + virtual sp<Fence> getAndResetReleaseFence() { + int fd = getLayer()->releaseFenceFd; + getLayer()->releaseFenceFd = -1; + return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE; + } + virtual void setAcquireFenceFd(int fenceFd) { + getLayer()->acquireFenceFd = fenceFd; + } + virtual void setPerFrameDefaultState() { + //getLayer()->compositionType = HWC_FRAMEBUFFER; + } + virtual void setPlaneAlpha(uint8_t alpha) { + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) { + getLayer()->planeAlpha = alpha; + } else { + if (alpha < 0xFF) { + getLayer()->flags |= HWC_SKIP_LAYER; + } + } + } + virtual void setDefaultState() { + hwc_layer_1_t* const l = getLayer(); + l->compositionType = HWC_FRAMEBUFFER; + l->hints = 0; + l->flags = HWC_SKIP_LAYER; + l->handle = 0; + l->transform = 0; + l->blending = HWC_BLENDING_NONE; + l->visibleRegionScreen.numRects = 0; + l->visibleRegionScreen.rects = NULL; + l->acquireFenceFd = -1; + l->releaseFenceFd = -1; + l->planeAlpha = 0xFF; + } + virtual void setSkip(bool skip) { + if (skip) { + getLayer()->flags |= HWC_SKIP_LAYER; + } else { + getLayer()->flags &= ~HWC_SKIP_LAYER; + } + } + virtual void setIsCursorLayerHint(bool isCursor) { + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) { + if (isCursor) { + getLayer()->flags |= HWC_IS_CURSOR_LAYER; + } + else { + getLayer()->flags &= ~HWC_IS_CURSOR_LAYER; + } + } + } + virtual void setBlending(uint32_t blending) { + getLayer()->blending = blending; + } + virtual void setTransform(uint32_t transform) { + getLayer()->transform = transform; + } + virtual void setFrame(const Rect& frame) { + getLayer()->displayFrame = reinterpret_cast<hwc_rect_t const&>(frame); + } + virtual void setCrop(const FloatRect& crop) { + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { + getLayer()->sourceCropf = reinterpret_cast<hwc_frect_t const&>(crop); + } else { + /* + * Since h/w composer didn't support a flot crop rect before version 1.3, + * using integer coordinates instead produces a different output from the GL code in + * Layer::drawWithOpenGL(). The difference can be large if the buffer crop to + * window size ratio is large and a window crop is defined + * (i.e.: if we scale the buffer a lot and we also crop it with a window crop). + */ + hwc_rect_t& r = getLayer()->sourceCrop; + r.left = int(ceilf(crop.left)); + r.top = int(ceilf(crop.top)); + r.right = int(floorf(crop.right)); + r.bottom= int(floorf(crop.bottom)); + } + } + virtual void setVisibleRegionScreen(const Region& reg) { + hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen; + mVisibleRegions->editItemAt(mIndex) = reg; + visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>( + mVisibleRegions->itemAt(mIndex).getArray( + &visibleRegion.numRects)); + } + virtual void setSurfaceDamage(const Region& reg) { + if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_5)) { + return; + } + hwc_region_t& surfaceDamage = getLayer()->surfaceDamage; + // We encode default full-screen damage as INVALID_RECT upstream, but as + // 0 rects for HWComposer + if (reg.isRect() && reg.getBounds() == Rect::INVALID_RECT) { + surfaceDamage.numRects = 0; + surfaceDamage.rects = NULL; + return; + } + mSurfaceDamageRegions->editItemAt(mIndex) = reg; + surfaceDamage.rects = reinterpret_cast<hwc_rect_t const *>( + mSurfaceDamageRegions->itemAt(mIndex).getArray( + &surfaceDamage.numRects)); + } + virtual void setSidebandStream(const sp<NativeHandle>& stream) { + ALOG_ASSERT(stream->handle() != NULL); + getLayer()->compositionType = HWC_SIDEBAND; + getLayer()->sidebandStream = stream->handle(); + } + virtual void setBuffer(const sp<GraphicBuffer>& buffer) { + if (buffer == 0 || buffer->handle == 0) { + getLayer()->compositionType = HWC_FRAMEBUFFER; + getLayer()->flags |= HWC_SKIP_LAYER; + getLayer()->handle = 0; + } else { + if (getLayer()->compositionType == HWC_SIDEBAND) { + // If this was a sideband layer but the stream was removed, reset + // it to FRAMEBUFFER. The HWC can change it to OVERLAY in prepare. + getLayer()->compositionType = HWC_FRAMEBUFFER; + } + getLayer()->handle = buffer->handle; + } + } + virtual void onDisplayed() { + getLayer()->acquireFenceFd = -1; + } + +protected: + // Pointers to the vectors of Region backing-memory held in DisplayData. + // Only the Region at mIndex corresponds to this Layer. + Vector<Region>* mVisibleRegions; + Vector<Region>* mSurfaceDamageRegions; +}; + +/* + * returns an iterator initialized at a given index in the layer list + */ +HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) { + if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) { + return LayerListIterator(); + } + DisplayData& disp(mDisplayData[id]); + if (!mHwc || !disp.list || index > disp.list->numHwLayers) { + return LayerListIterator(); + } + if (disp.visibleRegions.size() < disp.list->numHwLayers) { + disp.visibleRegions.resize(disp.list->numHwLayers); + } + if (disp.surfaceDamageRegions.size() < disp.list->numHwLayers) { + disp.surfaceDamageRegions.resize(disp.list->numHwLayers); + } + return LayerListIterator(new HWCLayerVersion1(mHwc, disp.list->hwLayers, + &disp.visibleRegions, &disp.surfaceDamageRegions), index); +} + +/* + * returns an iterator on the beginning of the layer list + */ +HWComposer::LayerListIterator HWComposer::begin(int32_t id) { + return getLayerIterator(id, 0); +} + +/* + * returns an iterator on the end of the layer list + */ +HWComposer::LayerListIterator HWComposer::end(int32_t id) { + size_t numLayers = 0; + if (uint32_t(id) <= 31 && mAllocatedDisplayIDs.hasBit(id)) { + const DisplayData& disp(mDisplayData[id]); + if (mHwc && disp.list) { + numLayers = disp.list->numHwLayers; + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { + // with HWC 1.1, the last layer is always the HWC_FRAMEBUFFER_TARGET, + // which we ignore when iterating through the layer list. + ALOGE_IF(!numLayers, "mDisplayData[%d].list->numHwLayers is 0", id); + if (numLayers) { + numLayers--; + } + } + } + } + return getLayerIterator(id, numLayers); +} + +// Converts a PixelFormat to a human-readable string. Max 11 chars. +// (Could use a table of prefab String8 objects.) +static String8 getFormatStr(PixelFormat format) { + switch (format) { + case PIXEL_FORMAT_RGBA_8888: return String8("RGBA_8888"); + case PIXEL_FORMAT_RGBX_8888: return String8("RGBx_8888"); + case PIXEL_FORMAT_RGB_888: return String8("RGB_888"); + case PIXEL_FORMAT_RGB_565: return String8("RGB_565"); + case PIXEL_FORMAT_BGRA_8888: return String8("BGRA_8888"); + case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: + return String8("ImplDef"); + default: + String8 result; + result.appendFormat("? %08x", format); + return result; + } +} + +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); + for (size_t i=0 ; i<mNumDisplays ; i++) { + const DisplayData& disp(mDisplayData[i]); + if (!disp.connected) + continue; + + const Vector< sp<Layer> >& visibleLayersSortedByZ = + mFlinger->getLayerSortedByZForHwcDisplay(i); + + + result.appendFormat(" Display[%zd] configurations (* current):\n", i); + for (size_t c = 0; c < disp.configs.size(); ++c) { + const DisplayConfig& config(disp.configs[c]); + result.appendFormat(" %s%zd: %ux%u, xdpi=%f, ydpi=%f" + ", refresh=%" PRId64 ", colorMode=%d\n", + c == disp.currentConfig ? "* " : "", c, + config.width, config.height, config.xdpi, config.ydpi, + config.refresh, config.colorMode); + } + + if (disp.list) { + result.appendFormat( + " numHwLayers=%zu, flags=%08x\n", + disp.list->numHwLayers, disp.list->flags); + + result.append( + " type | handle | hint | flag | tr | blnd | format | source crop (l,t,r,b) | frame | name \n" + "-----------+----------+------+------+----+------+-------------+--------------------------------+------------------------+------\n"); + // " _________ | ________ | ____ | ____ | __ | ____ | ___________ |_____._,_____._,_____._,_____._ |_____,_____,_____,_____ | ___... + for (size_t i=0 ; i<disp.list->numHwLayers ; i++) { + const hwc_layer_1_t&l = disp.list->hwLayers[i]; + int32_t format = -1; + String8 name("unknown"); + + if (i < visibleLayersSortedByZ.size()) { + const sp<Layer>& layer(visibleLayersSortedByZ[i]); + const sp<GraphicBuffer>& buffer( + layer->getActiveBuffer()); + if (buffer != NULL) { + format = buffer->getPixelFormat(); + } + name = layer->getName(); + } + + int type = l.compositionType; + if (type == HWC_FRAMEBUFFER_TARGET) { + name = "HWC_FRAMEBUFFER_TARGET"; + format = disp.format; + } + + static char const* compositionTypeName[] = { + "GLES", + "HWC", + "BKGND", + "FB TARGET", + "SIDEBAND", + "HWC_CURSOR", + "UNKNOWN"}; + if (type >= NELEM(compositionTypeName)) + type = NELEM(compositionTypeName) - 1; + + String8 formatStr = getFormatStr(format); + if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { + result.appendFormat( + " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7.1f,%7.1f,%7.1f,%7.1f |%5d,%5d,%5d,%5d | %s\n", + compositionTypeName[type], + intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(), + l.sourceCropf.left, l.sourceCropf.top, l.sourceCropf.right, l.sourceCropf.bottom, + l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom, + name.string()); + } else { + result.appendFormat( + " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7d,%7d,%7d,%7d |%5d,%5d,%5d,%5d | %s\n", + compositionTypeName[type], + intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(), + l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom, + l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom, + name.string()); + } + } + } + } + } + + if (mHwc && mHwc->dump) { + const size_t SIZE = 4096; + char buffer[SIZE]; + mHwc->dump(mHwc, buffer, SIZE); + result.append(buffer); + } +} + +// --------------------------------------------------------------------------- + +HWComposer::VSyncThread::VSyncThread(HWComposer& hwc) + : mHwc(hwc), mEnabled(false), + mNextFakeVSync(0), + mRefreshPeriod(hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY)) +{ +} + +void HWComposer::VSyncThread::setEnabled(bool enabled) { + Mutex::Autolock _l(mLock); + if (mEnabled != enabled) { + mEnabled = enabled; + mCondition.signal(); + } +} + +void HWComposer::VSyncThread::onFirstRef() { + run("VSyncThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); +} + +bool HWComposer::VSyncThread::threadLoop() { + { // scope for lock + Mutex::Autolock _l(mLock); + while (!mEnabled) { + mCondition.wait(mLock); + } + } + + const nsecs_t period = mRefreshPeriod; + const nsecs_t now = systemTime(CLOCK_MONOTONIC); + nsecs_t next_vsync = mNextFakeVSync; + nsecs_t sleep = next_vsync - now; + if (sleep < 0) { + // we missed, find where the next vsync should be + sleep = (period - ((now - next_vsync) % period)); + next_vsync = now + sleep; + } + mNextFakeVSync = next_vsync + period; + + struct timespec spec; + spec.tv_sec = next_vsync / 1000000000; + spec.tv_nsec = next_vsync % 1000000000; + + int err; + do { + err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL); + } while (err<0 && errno == EINTR); + + if (err == 0) { + mHwc.mEventHandler.onVSyncReceived(0, next_vsync); + } + + return true; +} + +HWComposer::DisplayData::DisplayData() +: configs(), + currentConfig(0), + format(HAL_PIXEL_FORMAT_RGBA_8888), + connected(false), + hasFbComp(false), hasOvComp(false), + capacity(0), list(NULL), + framebufferTarget(NULL), fbTargetHandle(0), + lastRetireFence(Fence::NO_FENCE), lastDisplayFence(Fence::NO_FENCE), + outbufHandle(NULL), outbufAcquireFence(Fence::NO_FENCE), + events(0) +{} + +HWComposer::DisplayData::~DisplayData() { + free(list); +} + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h new file mode 100644 index 0000000000..170e382330 --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2010 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_SF_HWCOMPOSER_HWC1_H +#define ANDROID_SF_HWCOMPOSER_HWC1_H + +#include <stdint.h> +#include <sys/types.h> + +#include <hardware/hwcomposer_defs.h> + +#include <system/graphics.h> + +#include <ui/Fence.h> + +#include <utils/BitSet.h> +#include <utils/Condition.h> +#include <utils/Mutex.h> +#include <utils/StrongPointer.h> +#include <utils/Thread.h> +#include <utils/Timers.h> +#include <utils/Vector.h> + +extern "C" int clock_nanosleep(clockid_t clock_id, int flags, + const struct timespec *request, + struct timespec *remain); + +struct hwc_composer_device_1; +struct hwc_display_contents_1; +struct hwc_layer_1; +struct hwc_procs; +struct framebuffer_device_t; + +namespace android { +// --------------------------------------------------------------------------- + +class Fence; +class FloatRect; +class GraphicBuffer; +class NativeHandle; +class Region; +class String8; +class SurfaceFlinger; + +class HWComposer +{ +public: + class EventHandler { + friend class HWComposer; + virtual void onVSyncReceived(int disp, nsecs_t timestamp) = 0; + virtual void onHotplugReceived(int disp, bool connected) = 0; + protected: + virtual ~EventHandler() {} + }; + + enum { + NUM_BUILTIN_DISPLAYS = HWC_NUM_PHYSICAL_DISPLAY_TYPES, + MAX_HWC_DISPLAYS = HWC_NUM_DISPLAY_TYPES, + VIRTUAL_DISPLAY_ID_BASE = HWC_DISPLAY_VIRTUAL, + }; + + HWComposer( + const sp<SurfaceFlinger>& flinger, + EventHandler& handler); + + ~HWComposer(); + + status_t initCheck() const; + + // Returns a display ID starting at VIRTUAL_DISPLAY_ID_BASE, this ID is to + // be used with createWorkList (and all other methods requiring an ID + // below). + // IDs below NUM_BUILTIN_DISPLAYS are pre-defined and therefore are + // always valid. + // Returns -1 if an ID cannot be allocated + int32_t allocateDisplayId(); + + // Recycles the given virtual display ID and frees the associated worklist. + // IDs below NUM_BUILTIN_DISPLAYS are not recycled. + status_t freeDisplayId(int32_t id); + + + // Asks the HAL what it can do + status_t prepare(); + + // commits the list + status_t commit(); + + // set power mode + status_t setPowerMode(int disp, int mode); + + // set active config + status_t setActiveConfig(int disp, int mode); + + // reset state when an external, non-virtual display is disconnected + void disconnectDisplay(int disp); + + // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED. + status_t createWorkList(int32_t id, size_t numLayers); + + bool supportsFramebufferTarget() const; + + // does this display have layers handled by HWC + bool hasHwcComposition(int32_t id) const; + + // does this display have layers handled by GLES + bool hasGlesComposition(int32_t id) const; + + // get the releaseFence file descriptor for a display's framebuffer layer. + // the release fence is only valid after commit() + sp<Fence> getAndResetReleaseFence(int32_t id); + + // needed forward declarations + class LayerListIterator; + + // return the visual id to be used to find a suitable EGLConfig for + // *ALL* displays. + int getVisualID() const; + + // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface). + int fbPost(int32_t id, const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf); + int fbCompositionComplete(); + void fbDump(String8& result); + + // Set the output buffer and acquire fence for a virtual display. + // Returns INVALID_OPERATION if id is not a virtual display. + status_t setOutputBuffer(int32_t id, const sp<Fence>& acquireFence, + const sp<GraphicBuffer>& buf); + + // Get the retire fence for the last committed frame. This fence will + // signal when the h/w composer is completely finished with the frame. + // For physical displays, it is no longer being displayed. For virtual + // displays, writes to the output buffer are complete. + sp<Fence> getLastRetireFence(int32_t id) const; + + status_t setCursorPositionAsync(int32_t id, const Rect &pos); + + /* + * Interface to hardware composer's layers functionality. + * This abstracts the HAL interface to layers which can evolve in + * incompatible ways from one release to another. + * The idea is that we could extend this interface as we add + * features to h/w composer. + */ + class HWCLayerInterface { + protected: + virtual ~HWCLayerInterface() { } + public: + virtual int32_t getCompositionType() const = 0; + virtual uint32_t getHints() const = 0; + virtual sp<Fence> getAndResetReleaseFence() = 0; + virtual void setDefaultState() = 0; + virtual void setSkip(bool skip) = 0; + virtual void setIsCursorLayerHint(bool isCursor = true) = 0; + virtual void setBlending(uint32_t blending) = 0; + virtual void setTransform(uint32_t transform) = 0; + virtual void setFrame(const Rect& frame) = 0; + virtual void setCrop(const FloatRect& crop) = 0; + virtual void setVisibleRegionScreen(const Region& reg) = 0; + virtual void setSurfaceDamage(const Region& reg) = 0; + virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0; + virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0; + virtual void setAcquireFenceFd(int fenceFd) = 0; + virtual void setPlaneAlpha(uint8_t alpha) = 0; + virtual void onDisplayed() = 0; + }; + + /* + * Interface used to implement an iterator to a list + * of HWCLayer. + */ + class HWCLayer : public HWCLayerInterface { + friend class LayerListIterator; + // select the layer at the given index + virtual status_t setLayer(size_t index) = 0; + virtual HWCLayer* dup() = 0; + static HWCLayer* copy(HWCLayer *rhs) { + return rhs ? rhs->dup() : NULL; + } + protected: + virtual ~HWCLayer() { } + }; + + /* + * Iterator through a HWCLayer list. + * This behaves more or less like a forward iterator. + */ + class LayerListIterator { + friend class HWComposer; + HWCLayer* const mLayerList; + size_t mIndex; + + LayerListIterator() : mLayerList(NULL), mIndex(0) { } + + LayerListIterator(HWCLayer* layer, size_t index) + : mLayerList(layer), mIndex(index) { } + + // we don't allow assignment, because we don't need it for now + LayerListIterator& operator = (const LayerListIterator& rhs); + + public: + // copy operators + LayerListIterator(const LayerListIterator& rhs) + : mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) { + } + + ~LayerListIterator() { delete mLayerList; } + + // pre-increment + LayerListIterator& operator++() { + mLayerList->setLayer(++mIndex); + return *this; + } + + // dereference + HWCLayerInterface& operator * () { return *mLayerList; } + HWCLayerInterface* operator -> () { return mLayerList; } + + // comparison + bool operator == (const LayerListIterator& rhs) const { + return mIndex == rhs.mIndex; + } + bool operator != (const LayerListIterator& rhs) const { + return !operator==(rhs); + } + }; + + // Returns an iterator to the beginning of the layer list + LayerListIterator begin(int32_t id); + + // Returns an iterator to the end of the layer list + LayerListIterator end(int32_t id); + + + // Events handling --------------------------------------------------------- + + enum { + EVENT_VSYNC = HWC_EVENT_VSYNC + }; + + void eventControl(int disp, int event, int enabled); + + struct DisplayConfig { + uint32_t width; + uint32_t height; + float xdpi; + float ydpi; + nsecs_t refresh; + android_color_mode_t colorMode; + bool operator==(const DisplayConfig& rhs) const { + return width == rhs.width && + height == rhs.height && + xdpi == rhs.xdpi && + ydpi == rhs.ydpi && + refresh == rhs.refresh && + colorMode == rhs.colorMode; + } + }; + + // Query display parameters. Pass in a display index (e.g. + // HWC_DISPLAY_PRIMARY). + nsecs_t getRefreshTimestamp(int disp) const; + sp<Fence> getDisplayFence(int disp) const; + uint32_t getFormat(int disp) const; + bool isConnected(int disp) const; + + // These return the values for the current config of a given display index. + // To get the values for all configs, use getConfigs below. + uint32_t getWidth(int disp) const; + uint32_t getHeight(int disp) const; + float getDpiX(int disp) const; + float getDpiY(int disp) const; + nsecs_t getRefreshPeriod(int disp) const; + android_color_mode_t getColorMode(int disp) const; + + const Vector<DisplayConfig>& getConfigs(int disp) const; + size_t getCurrentConfig(int disp) const; + + status_t setVirtualDisplayProperties(int32_t id, uint32_t w, uint32_t h, + uint32_t format); + + // this class is only used to fake the VSync event on systems that don't + // have it. + class VSyncThread : public Thread { + HWComposer& mHwc; + mutable Mutex mLock; + Condition mCondition; + bool mEnabled; + mutable nsecs_t mNextFakeVSync; + nsecs_t mRefreshPeriod; + virtual void onFirstRef(); + virtual bool threadLoop(); + public: + VSyncThread(HWComposer& hwc); + void setEnabled(bool enabled); + }; + + friend class VSyncThread; + + // for debugging ---------------------------------------------------------- + void dump(String8& out) const; + +private: + void loadHwcModule(); + int loadFbHalModule(); + + LayerListIterator getLayerIterator(int32_t id, size_t index); + + struct cb_context; + + static void hook_invalidate(const struct hwc_procs* procs); + static void hook_vsync(const struct hwc_procs* procs, int disp, + int64_t timestamp); + static void hook_hotplug(const struct hwc_procs* procs, int disp, + int connected); + + inline void invalidate(); + inline void vsync(int disp, int64_t timestamp); + inline void hotplug(int disp, int connected); + + status_t queryDisplayProperties(int disp); + + status_t setFramebufferTarget(int32_t id, + const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf); + + struct DisplayData { + DisplayData(); + ~DisplayData(); + Vector<DisplayConfig> configs; + size_t currentConfig; + uint32_t format; // pixel format from FB hal, for pre-hwc-1.1 + bool connected; + bool hasFbComp; + bool hasOvComp; + size_t capacity; + hwc_display_contents_1* list; + hwc_layer_1* framebufferTarget; + buffer_handle_t fbTargetHandle; + sp<Fence> lastRetireFence; // signals when the last set op retires + sp<Fence> lastDisplayFence; // signals when the last set op takes + // effect on screen + buffer_handle_t outbufHandle; + sp<Fence> outbufAcquireFence; + + // protected by mEventControlLock + int32_t events; + + // We need to hold "copies" of these for memory management purposes. The + // actual hwc_layer_1_t holds pointers to the memory within. Vector<> + // internally doesn't copy the memory unless one of the copies is + // modified. + Vector<Region> visibleRegions; + Vector<Region> surfaceDamageRegions; + }; + + sp<SurfaceFlinger> mFlinger; + framebuffer_device_t* mFbDev; + struct hwc_composer_device_1* mHwc; + // invariant: mLists[0] != NULL iff mHwc != NULL + // 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; + EventHandler& mEventHandler; + size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES]; + sp<VSyncThread> mVSyncThread; + bool mDebugForceFakeVSync; + BitSet32 mAllocatedDisplayIDs; + + // protected by mLock + mutable Mutex mLock; + mutable nsecs_t mLastHwVSync[HWC_NUM_PHYSICAL_DISPLAY_TYPES]; + + // thread-safe + mutable Mutex mEventControlLock; +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SF_HWCOMPOSER_H diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index a9271c2399..2190466ad9 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -175,6 +175,12 @@ status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { return NO_ERROR; } +#ifndef USE_HWC2 +status_t VirtualDisplaySurface::compositionComplete() { + return NO_ERROR; +} +#endif + status_t VirtualDisplaySurface::advanceFrame() { if (mDisplayId < 0) return NO_ERROR; @@ -214,9 +220,13 @@ status_t VirtualDisplaySurface::advanceFrame() { status_t result = NO_ERROR; if (fbBuffer != NULL) { +#ifdef USE_HWC2 // TODO: Correctly propagate the dataspace from GL composition result = mHwc.setClientTarget(mDisplayId, mFbFence, fbBuffer, HAL_DATASPACE_UNKNOWN); +#else + result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer); +#endif } return result; @@ -230,14 +240,22 @@ void VirtualDisplaySurface::onFrameCommitted() { "Unexpected onFrameCommitted() in %s state", dbgStateStr()); mDbgState = DBG_STATE_IDLE; +#ifdef USE_HWC2 sp<Fence> retireFence = mHwc.getRetireFence(mDisplayId); +#else + sp<Fence> fbFence = mHwc.getAndResetReleaseFence(mDisplayId); +#endif if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) { // release the scratch buffer back to the pool Mutex::Autolock lock(mMutex); int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot); VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot); +#ifdef USE_HWC2 addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], retireFence); +#else + addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence); +#endif releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot], EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); } @@ -245,6 +263,9 @@ void VirtualDisplaySurface::onFrameCommitted() { if (mOutputProducerSlot >= 0) { int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot); QueueBufferOutput qbo; +#ifndef USE_HWC2 + sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId); +#endif VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot); if (mMustRecompose) { status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, @@ -253,7 +274,11 @@ void VirtualDisplaySurface::onFrameCommitted() { HAL_DATASPACE_UNKNOWN, Rect(mSinkBufferWidth, mSinkBufferHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */, +#ifdef USE_HWC2 retireFence), +#else + outFence), +#endif &qbo); if (result == NO_ERROR) { updateQueueBufferOutput(qbo); @@ -263,7 +288,11 @@ void VirtualDisplaySurface::onFrameCommitted() { // through the motions of updating the display to keep our state // machine happy. We cancel the buffer to avoid triggering another // re-composition and causing an infinite loop. +#ifdef USE_HWC2 mSource[SOURCE_SINK]->cancelBuffer(sslot, retireFence); +#else + mSource[SOURCE_SINK]->cancelBuffer(sslot, outFence); +#endif } } diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 884460d510..70f717f8c2 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -83,6 +83,9 @@ public: // virtual status_t beginFrame(bool mustRecompose); virtual status_t prepareFrame(CompositionType compositionType); +#ifndef USE_HWC2 + virtual status_t compositionComplete(); +#endif virtual status_t advanceFrame(); virtual void onFrameCommitted(); virtual void dumpAsString(String8& result) const; diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp index 26822c87c7..ee6e886d12 100644 --- a/services/surfaceflinger/EventControlThread.cpp +++ b/services/surfaceflinger/EventControlThread.cpp @@ -35,7 +35,12 @@ bool EventControlThread::threadLoop() { bool vsyncEnabled = mVsyncEnabled; +#ifdef USE_HWC2 mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled); +#else + mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, + mVsyncEnabled); +#endif while (true) { status_t err = mCond.wait(mMutex); @@ -46,7 +51,12 @@ bool EventControlThread::threadLoop() { } if (vsyncEnabled != mVsyncEnabled) { +#ifdef USE_HWC2 mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled); +#else + mFlinger->eventControl(HWC_DISPLAY_PRIMARY, + SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled); +#endif vsyncEnabled = mVsyncEnabled; } } diff --git a/services/surfaceflinger/FenceTracker.cpp b/services/surfaceflinger/FenceTracker.cpp index a3aaf4271a..0e18a937e4 100644 --- a/services/surfaceflinger/FenceTracker.cpp +++ b/services/surfaceflinger/FenceTracker.cpp @@ -141,6 +141,7 @@ void FenceTracker::addFrame(nsecs_t refreshStartTime, sp<Fence> retireFence, layers[i]->getFenceData(&name, &frameNumber, &glesComposition, &postedTime, &acquireFence, &prevReleaseFence); +#ifdef USE_HWC2 if (glesComposition) { frame.layers.emplace(std::piecewise_construct, std::forward_as_tuple(layerId), @@ -157,6 +158,16 @@ void FenceTracker::addFrame(nsecs_t refreshStartTime, sp<Fence> retireFence, prevLayer->second.releaseFence = prevReleaseFence; } } +#else + frame.layers.emplace(std::piecewise_construct, + std::forward_as_tuple(layerId), + std::forward_as_tuple(name, frameNumber, glesComposition, + postedTime, 0, 0, acquireFence, + glesComposition ? Fence::NO_FENCE : prevReleaseFence)); + if (glesComposition) { + wasGlesCompositionDone = true; + } +#endif frame.layers.emplace(std::piecewise_construct, std::forward_as_tuple(layerId), std::forward_as_tuple(name, frameNumber, glesComposition, diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 9350fa52ff..6a3d62becd 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -85,6 +85,9 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mFiltering(false), mNeedsFiltering(false), mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2), +#ifndef USE_HWC2 + mIsGlesComposition(false), +#endif mProtectedByApp(false), mHasSurface(false), mClientRef(client), @@ -97,7 +100,9 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mAutoRefresh(false), mFreezePositionUpdates(false) { +#ifdef USE_HWC2 ALOGV("Creating Layer %s", name.string()); +#endif mCurrentCrop.makeInvalid(); mFlinger->getRenderEngine().genTextures(1, &mTextureName); @@ -122,7 +127,11 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mCurrentState.crop.makeInvalid(); mCurrentState.finalCrop.makeInvalid(); mCurrentState.z = 0; +#ifdef USE_HWC2 mCurrentState.alpha = 1.0f; +#else + mCurrentState.alpha = 0xFF; +#endif mCurrentState.layerStack = 0; mCurrentState.flags = layerFlags; mCurrentState.sequence = 0; @@ -131,9 +140,14 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, // drawing state & current state are identical mDrawingState = mCurrentState; +#ifdef USE_HWC2 const auto& hwc = flinger->getHwComposer(); const auto& activeConfig = hwc.getActiveConfig(HWC_DISPLAY_PRIMARY); nsecs_t displayPeriod = activeConfig->getVsyncPeriod(); +#else + nsecs_t displayPeriod = + flinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); +#endif mFrameTracker.setDisplayRefreshPeriod(displayPeriod); } @@ -176,12 +190,22 @@ Layer::~Layer() { // callbacks // --------------------------------------------------------------------------- +#ifdef USE_HWC2 void Layer::onLayerDisplayed(const sp<Fence>& releaseFence) { if (mHwcLayers.empty()) { return; } mSurfaceFlingerConsumer->setReleaseFence(releaseFence); } +#else +void Layer::onLayerDisplayed(const sp<const DisplayDevice>& /* hw */, + HWComposer::HWCLayerInterface* layer) { + if (layer) { + layer->onDisplayed(); + mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFence()); + } +} +#endif void Layer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker @@ -453,12 +477,23 @@ FloatRect Layer::computeCrop(const sp<const DisplayDevice>& hw) const { return crop; } +#ifdef USE_HWC2 void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice) +#else +void Layer::setGeometry( + const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) +#endif { +#ifdef USE_HWC2 const auto hwcId = displayDevice->getHwcDisplayId(); auto& hwcInfo = mHwcLayers[hwcId]; +#else + layer.setDefaultState(); +#endif // enable this layer +#ifdef USE_HWC2 hwcInfo.forceClientComposition = false; if (isSecure() && !displayDevice->isSecure()) { @@ -466,9 +501,17 @@ void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice) } auto& hwcLayer = hwcInfo.layer; +#else + layer.setSkip(false); + + if (isSecure() && !hw->isSecure()) { + layer.setSkip(true); + } +#endif // this gives us only the "orientation" component of the transform const State& s(getDrawingState()); +#ifdef USE_HWC2 if (!isOpaque(s) || s.alpha != 1.0f) { auto blendMode = mPremultipliedAlpha ? HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage; @@ -477,6 +520,13 @@ void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice) " %s (%d)", mName.string(), to_string(blendMode).c_str(), to_string(error).c_str(), static_cast<int32_t>(error)); } +#else + if (!isOpaque(s) || s.alpha != 0xFF) { + layer.setBlending(mPremultipliedAlpha ? + HWC_BLENDING_PREMULT : + HWC_BLENDING_COVERAGE); + } +#endif // apply the layer's transform, followed by the display's global transform // here we're guaranteed that the layer's transform preserves rects @@ -484,7 +534,11 @@ void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice) if (!s.crop.isEmpty()) { Rect activeCrop(s.crop); activeCrop = s.active.transform.transform(activeCrop); +#ifdef USE_HWC2 if(!activeCrop.intersect(displayDevice->getViewport(), &activeCrop)) { +#else + if(!activeCrop.intersect(hw->getViewport(), &activeCrop)) { +#endif activeCrop.clear(); } activeCrop = s.active.transform.inverse().transform(activeCrop, true); @@ -512,6 +566,7 @@ void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice) frame.clear(); } } +#ifdef USE_HWC2 if (!frame.intersect(displayDevice->getViewport(), &frame)) { frame.clear(); } @@ -547,6 +602,15 @@ void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice) ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)", mName.string(), s.z, to_string(error).c_str(), static_cast<int32_t>(error)); +#else + if (!frame.intersect(hw->getViewport(), &frame)) { + frame.clear(); + } + const Transform& tr(hw->getTransform()); + layer.setFrame(tr.transform(frame)); + layer.setCrop(computeCrop(hw)); + layer.setPlaneAlpha(s.alpha); +#endif /* * Transformations are applied in this order: @@ -577,6 +641,7 @@ void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice) // this gives us only the "orientation" component of the transform const uint32_t orientation = transform.getOrientation(); +#ifdef USE_HWC2 if (orientation & Transform::ROT_INVALID) { // we can only handle simple transformation hwcInfo.forceClientComposition = true; @@ -587,8 +652,17 @@ void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice) "%s (%d)", mName.string(), to_string(transform).c_str(), to_string(error).c_str(), static_cast<int32_t>(error)); } +#else + if (orientation & Transform::ROT_INVALID) { + // we can only handle simple transformation + layer.setSkip(true); + } else { + layer.setTransform(orientation); + } +#endif } +#ifdef USE_HWC2 void Layer::forceClientComposition(int32_t hwcId) { if (mHwcLayers.count(hwcId) == 0) { ALOGE("forceClientComposition: no HWC layer found (%d)", hwcId); @@ -597,7 +671,9 @@ void Layer::forceClientComposition(int32_t hwcId) { mHwcLayers[hwcId].forceClientComposition = true; } +#endif +#ifdef USE_HWC2 void Layer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) { // Apply this display's projection's viewport to the visible region // before giving it to the HWC HAL. @@ -680,7 +756,31 @@ void Layer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) { static_cast<int32_t>(error)); } } +#else +void Layer::setPerFrameData(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { + // we have to set the visible region on every frame because + // we currently free it during onLayerDisplayed(), which is called + // after HWComposer::commit() -- every frame. + // Apply this display's projection's viewport to the visible region + // before giving it to the HWC HAL. + const Transform& tr = hw->getTransform(); + Region visible = tr.transform(visibleRegion.intersect(hw->getViewport())); + layer.setVisibleRegionScreen(visible); + layer.setSurfaceDamage(surfaceDamageRegion); + mIsGlesComposition = (layer.getCompositionType() == HWC_FRAMEBUFFER); + if (mSidebandStream.get()) { + layer.setSidebandStream(mSidebandStream); + } else { + // NOTE: buffer can be NULL if the client never drew into this + // layer yet, or if we ran out of memory + layer.setBuffer(mActiveBuffer); + } +} +#endif + +#ifdef USE_HWC2 void Layer::updateCursorPosition(const sp<const DisplayDevice>& displayDevice) { auto hwcId = displayDevice->getHwcDisplayId(); if (mHwcLayers.count(hwcId) == 0 || @@ -714,6 +814,49 @@ void Layer::updateCursorPosition(const sp<const DisplayDevice>& displayDevice) { position.top, to_string(error).c_str(), static_cast<int32_t>(error)); } +#else +void Layer::setAcquireFence(const sp<const DisplayDevice>& /* hw */, + HWComposer::HWCLayerInterface& layer) { + int fenceFd = -1; + + // TODO: there is a possible optimization here: we only need to set the + // acquire fence the first time a new buffer is acquired on EACH display. + + if (layer.getCompositionType() == HWC_OVERLAY || layer.getCompositionType() == HWC_CURSOR_OVERLAY) { + sp<Fence> fence = mSurfaceFlingerConsumer->getCurrentFence(); + if (fence->isValid()) { + fenceFd = fence->dup(); + if (fenceFd == -1) { + ALOGW("failed to dup layer fence, skipping sync: %d", errno); + } + } + } + layer.setAcquireFenceFd(fenceFd); +} + +Rect Layer::getPosition( + const sp<const DisplayDevice>& hw) +{ + // this gives us only the "orientation" component of the transform + const State& s(getCurrentState()); + + // apply the layer's transform, followed by the display's global transform + // here we're guaranteed that the layer's transform preserves rects + Rect win(s.active.w, s.active.h); + if (!s.crop.isEmpty()) { + win.intersect(s.crop, &win); + } + // subtract the transparent region and snap to the bounds + Rect bounds = reduce(win, s.activeTransparentRegion); + Rect frame(s.active.transform.transform(bounds)); + frame.intersect(hw->getViewport(), &frame); + if (!s.finalCrop.isEmpty()) { + frame.intersect(s.finalCrop, &frame); + } + const Transform& tr(hw->getTransform()); + return Rect(tr.transform(frame)); +} +#endif // --------------------------------------------------------------------------- // drawing... @@ -898,6 +1041,7 @@ void Layer::drawWithOpenGL(const sp<const DisplayDevice>& hw, engine.disableBlending(); } +#ifdef USE_HWC2 void Layer::setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc) { if (mHwcLayers.count(hwcId) == 0) { @@ -949,6 +1093,7 @@ bool Layer::getClearClientTarget(int32_t hwcId) const { } return mHwcLayers.at(hwcId).clearClientTarget; } +#endif uint32_t Layer::getProducerStickyTransform() const { int producerStickyTransform = 0; @@ -985,6 +1130,7 @@ uint64_t Layer::getHeadFrameNumber() const { } bool Layer::headFenceHasSignaled() const { +#ifdef USE_HWC2 if (latchUnsignaledBuffers()) { return true; } @@ -1001,6 +1147,9 @@ bool Layer::headFenceHasSignaled() const { return true; } return mQueueItems[0].mFence->getSignalTime() != INT64_MAX; +#else + return true; +#endif } bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) { @@ -1440,7 +1589,11 @@ bool Layer::setSize(uint32_t w, uint32_t h) { setTransactionFlags(eTransactionNeeded); return true; } +#ifdef USE_HWC2 bool Layer::setAlpha(float alpha) { +#else +bool Layer::setAlpha(uint8_t alpha) { +#endif if (mCurrentState.alpha == alpha) return false; mCurrentState.sequence++; @@ -1595,7 +1748,11 @@ bool Layer::onPostComposition() { } const HWComposer& hwc = mFlinger->getHwComposer(); +#ifdef USE_HWC2 sp<Fence> presentFence = hwc.getRetireFence(HWC_DISPLAY_PRIMARY); +#else + sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY); +#endif if (presentFence->isValid()) { mFrameTracker.setActualPresentFence(presentFence); } else { @@ -1611,14 +1768,21 @@ bool Layer::onPostComposition() { return frameLatencyNeeded; } +#ifdef USE_HWC2 void Layer::releasePendingBuffer() { mSurfaceFlingerConsumer->releasePendingBuffer(); } +#endif bool Layer::isVisible() const { const Layer::State& s(mDrawingState); +#ifdef USE_HWC2 return !(s.flags & layer_state_t::eLayerHidden) && s.alpha > 0.0f && (mActiveBuffer != NULL || mSidebandStream != NULL); +#else + return !(s.flags & layer_state_t::eLayerHidden) && s.alpha + && (mActiveBuffer != NULL || mSidebandStream != NULL); +#endif } Region Layer::latchBuffer(bool& recomputeVisibleRegions) @@ -2022,7 +2186,11 @@ void Layer::dump(String8& result, Colorizer& colorizer) const "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), " "crop=(%4d,%4d,%4d,%4d), finalCrop=(%4d,%4d,%4d,%4d), " "isOpaque=%1d, invalidate=%1d, " +#ifdef USE_HWC2 "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" +#else + "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" +#endif " client=%p\n", s.layerStack, s.z, s.active.transform.tx(), s.active.transform.ty(), s.active.w, s.active.h, s.crop.left, s.crop.top, @@ -2055,6 +2223,7 @@ void Layer::dump(String8& result, Colorizer& colorizer) const } } +#ifdef USE_HWC2 void Layer::miniDumpHeader(String8& result) { result.append("----------------------------------------"); result.append("---------------------------------------\n"); @@ -2100,6 +2269,7 @@ void Layer::miniDump(String8& result, int32_t hwcId) const { result.append("- - - - - - - - - - - - - - - - - - - - "); result.append("- - - - - - - - - - - - - - - - - - - -\n"); } +#endif void Layer::dumpFrameStats(String8& result) const { mFrameTracker.dumpStats(result); @@ -2123,9 +2293,13 @@ void Layer::getFenceData(String8* outName, uint64_t* outFrameNumber, *outName = mName; *outFrameNumber = mSurfaceFlingerConsumer->getFrameNumber(); +#ifdef USE_HWC2 *outIsGlesComposition = mHwcLayers.count(HWC_DISPLAY_PRIMARY) ? mHwcLayers.at(HWC_DISPLAY_PRIMARY).compositionType == HWC2::Composition::Client : true; +#else + *outIsGlesComposition = mIsGlesComposition; +#endif *outPostedTime = mSurfaceFlingerConsumer->getTimestamp(); *outAcquireFence = mSurfaceFlingerConsumer->getCurrentFence(); *outPrevReleaseFence = mSurfaceFlingerConsumer->getPrevReleaseFence(); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 59129c7249..efb0fb8b50 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -110,7 +110,11 @@ public: Geometry requested; uint32_t z; uint32_t layerStack; +#ifdef USE_HWC2 float alpha; +#else + uint8_t alpha; +#endif uint8_t flags; uint8_t mask; uint8_t reserved[2]; @@ -148,7 +152,11 @@ public: bool setPosition(float x, float y, bool immediate); bool setLayer(uint32_t z); bool setSize(uint32_t w, uint32_t h); +#ifdef USE_HWC2 bool setAlpha(float alpha); +#else + bool setAlpha(uint8_t alpha); +#endif bool setMatrix(const layer_state_t::matrix22_t& matrix); bool setTransparentRegionHint(const Region& transparent); bool setFlags(uint8_t flags, uint8_t mask); @@ -220,6 +228,7 @@ protected: public: // ----------------------------------------------------------------------- +#ifdef USE_HWC2 void setGeometry(const sp<const DisplayDevice>& displayDevice); void forceClientComposition(int32_t hwcId); void setPerFrameData(const sp<const DisplayDevice>& displayDevice); @@ -234,11 +243,26 @@ public: bool getClearClientTarget(int32_t hwcId) const; void updateCursorPosition(const sp<const DisplayDevice>& hw); +#else + void setGeometry(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); + void setPerFrameData(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); + void setAcquireFence(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); + + Rect getPosition(const sp<const DisplayDevice>& hw); +#endif /* * called after page-flip */ +#ifdef USE_HWC2 void onLayerDisplayed(const sp<Fence>& releaseFence); +#else + void onLayerDisplayed(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface* layer); +#endif bool shouldPresentNow(const DispSync& dispSync) const; @@ -254,8 +278,10 @@ public: */ bool onPostComposition(); +#ifdef USE_HWC2 // If a buffer was replaced this frame, release the former buffer void releasePendingBuffer(); +#endif /* * draw - performs some global clipping optimizations @@ -324,6 +350,7 @@ public: bool hasQueuedFrame() const { return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh; } +#ifdef USE_HWC2 // ----------------------------------------------------------------------- bool hasHwcLayer(int32_t hwcId) { @@ -353,6 +380,7 @@ public: } } +#endif // ----------------------------------------------------------------------- void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const; @@ -369,8 +397,10 @@ public: /* always call base class first */ void dump(String8& result, Colorizer& colorizer) const; +#ifdef USE_HWC2 static void miniDumpHeader(String8& result); void miniDump(String8& result, int32_t hwcId) const; +#endif void dumpFrameStats(String8& result) const; void clearFrameStats(); void logFrameStats(); @@ -571,6 +601,7 @@ private: // The texture used to draw the layer in GLES composition mode mutable Texture mTexture; +#ifdef USE_HWC2 // HWC items, accessed from the main thread struct HWCInfo { HWCInfo() @@ -587,6 +618,9 @@ private: FloatRect sourceCrop; }; std::unordered_map<int32_t, HWCInfo> mHwcLayers; +#else + bool mIsGlesComposition; +#endif // page-flip thread (currently main thread) bool mProtectedByApp; // application requires protected path to external sink diff --git a/services/surfaceflinger/RenderEngine/GLES10RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES10RenderEngine.cpp index 00b1cd27fc..579affb25d 100644 --- a/services/surfaceflinger/RenderEngine/GLES10RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES10RenderEngine.cpp @@ -28,25 +28,43 @@ GLES10RenderEngine::~GLES10RenderEngine() { } void GLES10RenderEngine::setupLayerBlending( +#ifdef USE_HWC2 bool premultipliedAlpha, bool opaque, float alpha) { +#else + bool premultipliedAlpha, bool opaque, int alpha) { +#endif // OpenGL ES 1.0 doesn't support texture combiners. // This path doesn't properly handle opaque layers that have non-opaque // alpha values. The alpha channel will be copied into the framebuffer or // screenshot, so if the framebuffer or screenshot is blended on top of // something else, whatever is below the window will incorrectly show // through. +#ifdef USE_HWC2 if (CC_UNLIKELY(alpha < 1.0f)) { if (premultipliedAlpha) { glColor4f(alpha, alpha, alpha, alpha); } else { glColor4f(1.0f, 1.0f, 1.0f, alpha); } +#else + if (CC_UNLIKELY(alpha < 0xFF)) { + GLfloat floatAlpha = alpha * (1.0f / 255.0f); + if (premultipliedAlpha) { + glColor4f(floatAlpha, floatAlpha, floatAlpha, floatAlpha); + } else { + glColor4f(1.0f, 1.0f, 1.0f, floatAlpha); + } +#endif glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } else { glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } +#ifdef USE_HWC2 if (alpha < 1.0f || !opaque) { +#else + if (alpha < 0xFF || !opaque) { +#endif glEnable(GL_BLEND); glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); diff --git a/services/surfaceflinger/RenderEngine/GLES10RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES10RenderEngine.h index c416408341..61abd6a679 100644 --- a/services/surfaceflinger/RenderEngine/GLES10RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES10RenderEngine.h @@ -30,8 +30,12 @@ namespace android { class GLES10RenderEngine : public GLES11RenderEngine { virtual ~GLES10RenderEngine(); protected: +#ifdef USE_HWC2 virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) override; +#else + virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha); +#endif }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp index a6d66f786c..847cdb388a 100644 --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp @@ -107,20 +107,33 @@ void GLES11RenderEngine::setViewportAndProjection( glMatrixMode(GL_MODELVIEW); } +#ifdef USE_HWC2 void GLES11RenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) { +#else +void GLES11RenderEngine::setupLayerBlending( + bool premultipliedAlpha, bool opaque, int alpha) { +#endif GLenum combineRGB; GLenum combineAlpha; GLenum src0Alpha; GLfloat envColor[4]; +#ifdef USE_HWC2 if (CC_UNLIKELY(alpha < 1.0f)) { +#else + if (CC_UNLIKELY(alpha < 0xFF)) { +#endif // Cv = premultiplied ? Cs*alpha : Cs // Av = !opaque ? As*alpha : As combineRGB = premultipliedAlpha ? GL_MODULATE : GL_REPLACE; combineAlpha = !opaque ? GL_MODULATE : GL_REPLACE; src0Alpha = GL_CONSTANT; +#ifdef USE_HWC2 envColor[0] = alpha; +#else + envColor[0] = alpha * (1.0f / 255.0f); +#endif } else { // Cv = Cs // Av = opaque ? 1.0 : As @@ -152,7 +165,11 @@ void GLES11RenderEngine::setupLayerBlending(bool premultipliedAlpha, glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor); } +#ifdef USE_HWC2 if (alpha < 1.0f || !opaque) { +#else + if (alpha < 0xFF || !opaque) { +#endif glEnable(GL_BLEND); glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -161,16 +178,28 @@ void GLES11RenderEngine::setupLayerBlending(bool premultipliedAlpha, } } +#ifdef USE_HWC2 void GLES11RenderEngine::setupDimLayerBlending(float alpha) { +#else +void GLES11RenderEngine::setupDimLayerBlending(int alpha) { +#endif glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_2D); +#ifdef USE_HWC2 if (alpha == 1.0f) { +#else + if (alpha == 0xFF) { +#endif glDisable(GL_BLEND); } else { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } +#ifdef USE_HWC2 glColor4f(0, 0, 0, alpha); +#else + glColor4f(0, 0, 0, alpha/255.0f); +#endif } void GLES11RenderEngine::setupLayerTexturing(const Texture& texture) { diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h index fdaa53343c..4cd968d125 100644 --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h @@ -53,9 +53,15 @@ protected: virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation); +#ifdef USE_HWC2 virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) override; virtual void setupDimLayerBlending(float alpha) override; +#else + virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, + int alpha); + virtual void setupDimLayerBlending(int alpha); +#endif virtual void setupLayerTexturing(const Texture& texture); virtual void setupLayerBlackedOut(); virtual void setupFillWithColor(float r, float g, float b, float a) ; diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp index 2503b27973..406e611eef 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp @@ -117,14 +117,25 @@ void GLES20RenderEngine::setViewportAndProjection( mVpHeight = vph; } +#ifdef USE_HWC2 void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) { +#else +void GLES20RenderEngine::setupLayerBlending( + bool premultipliedAlpha, bool opaque, int alpha) { +#endif mState.setPremultipliedAlpha(premultipliedAlpha); mState.setOpaque(opaque); +#ifdef USE_HWC2 mState.setPlaneAlpha(alpha); if (alpha < 1.0f || !opaque) { +#else + mState.setPlaneAlpha(alpha / 255.0f); + + if (alpha < 0xFF || !opaque) { +#endif glEnable(GL_BLEND); glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { @@ -132,14 +143,26 @@ void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, } } +#ifdef USE_HWC2 void GLES20RenderEngine::setupDimLayerBlending(float alpha) { +#else +void GLES20RenderEngine::setupDimLayerBlending(int alpha) { +#endif mState.setPlaneAlpha(1.0f); mState.setPremultipliedAlpha(true); mState.setOpaque(false); +#ifdef USE_HWC2 mState.setColor(0, 0, 0, alpha); +#else + mState.setColor(0, 0, 0, alpha/255.0f); +#endif mState.disableTexture(); +#ifdef USE_HWC2 if (alpha == 1.0f) { +#else + if (alpha == 0xFF) { +#endif glDisable(GL_BLEND); } else { glEnable(GL_BLEND); diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h index 735e17486a..7c3f9b5d4a 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h @@ -68,9 +68,15 @@ protected: virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation); +#ifdef USE_HWC2 virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) override; virtual void setupDimLayerBlending(float alpha) override; +#else + virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, + int alpha); + virtual void setupDimLayerBlending(int alpha); +#endif virtual void setupLayerTexturing(const Texture& texture); virtual void setupLayerBlackedOut(); virtual void setupFillWithColor(float r, float g, float b, float a); diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index bd45bae356..0259881eee 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -95,8 +95,13 @@ public: virtual void checkErrors() const; virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation) = 0; +#ifdef USE_HWC2 virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) = 0; virtual void setupDimLayerBlending(float alpha) = 0; +#else + virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha) = 0; + virtual void setupDimLayerBlending(int alpha) = 0; +#endif virtual void setupLayerTexturing(const Texture& texture) = 0; virtual void setupLayerBlackedOut() = 0; virtual void setupFillWithColor(float r, float g, float b, float a) = 0; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 9c37223f8c..6449e5781c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -129,7 +129,11 @@ public: // enable/disable h/w composer event // TODO: this should be made accessible only to EventThread +#ifdef USE_HWC2 void setVsyncEnabled(int disp, int enabled); +#else + void eventControl(int disp, int event, int enabled); +#endif // called on the main thread by MessageQueue when an internal message // is received @@ -377,6 +381,10 @@ private: // region of all screens presenting this layer stack. void invalidateLayerStack(uint32_t layerStack, const Region& dirty); +#ifndef USE_HWC2 + int32_t allocateHwcDisplayId(DisplayDevice::DisplayType type); +#endif + /* ------------------------------------------------------------------------ * H/W composer */ @@ -482,11 +490,17 @@ private: // don't need synchronization State mDrawingState; bool mVisibleRegionsDirty; +#ifndef USE_HWC2 + bool mHwWorkListDirty; +#else bool mGeometryInvalid; +#endif bool mAnimCompositionPending; +#ifdef USE_HWC2 std::vector<sp<Layer>> mLayersWithQueuedFrames; sp<Fence> mPreviousPresentFence = Fence::NO_FENCE; bool mHadClientComposition = false; +#endif // this may only be written from the main thread with mStateLock held // it may be read from other threads with mStateLock held @@ -504,7 +518,9 @@ private: bool mBootFinished; bool mForceFullDamage; FenceTracker mFenceTracker; +#ifdef USE_HWC2 bool mPropagateBackpressure = true; +#endif SurfaceInterceptor mInterceptor; bool mUseHwcVirtualDisplays = true; @@ -529,6 +545,9 @@ private: bool mInjectVSyncs; Daltonizer mDaltonizer; +#ifndef USE_HWC2 + bool mDaltonize; +#endif mat4 mPreviousColorMatrix; mat4 mColorMatrix; diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index eb78b67c2d..e0e4c61e69 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -88,7 +88,11 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter, } // Release the previous buffer. +#ifdef USE_HWC2 err = updateAndReleaseLocked(item, &mPendingRelease); +#else + err = updateAndReleaseLocked(item); +#endif if (err != NO_ERROR) { return err; } @@ -185,6 +189,7 @@ nsecs_t SurfaceFlingerConsumer::computeExpectedPresent(const DispSync& dispSync) return nextRefresh + extraPadding; } +#ifdef USE_HWC2 void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence) { mPrevReleaseFence = fence; @@ -217,6 +222,12 @@ void SurfaceFlingerConsumer::releasePendingBuffer() strerror(-result), result); mPendingRelease = PendingRelease(); } +#else +void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence) { + mPrevReleaseFence = fence; + GLConsumer::setReleaseFence(fence); +} +#endif sp<Fence> SurfaceFlingerConsumer::getPrevReleaseFence() const { return mPrevReleaseFence; diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h index 0f9a0b4a5d..4271039d25 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.h +++ b/services/surfaceflinger/SurfaceFlingerConsumer.h @@ -81,7 +81,9 @@ public: virtual void setReleaseFence(const sp<Fence>& fence) override; sp<Fence> getPrevReleaseFence() const; +#ifdef USE_HWC2 void releasePendingBuffer(); +#endif virtual bool getFrameTimestamps(uint64_t frameNumber, FrameTimestamps* outTimestamps) const override; @@ -99,9 +101,11 @@ private: // The portion of this surface that has changed since the previous frame Region mSurfaceDamage; +#ifdef USE_HWC2 // A release that is pending on the receipt of a new release fence from // presentDisplay PendingRelease mPendingRelease; +#endif // The release fence of the already displayed buffer (previous frame). sp<Fence> mPrevReleaseFence; diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp new file mode 100644 index 0000000000..3ae2c040b2 --- /dev/null +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -0,0 +1,3827 @@ +/* + * Copyright (C) 2007 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 <stdint.h> +#include <sys/types.h> +#include <errno.h> +#include <math.h> +#include <mutex> +#include <dlfcn.h> +#include <inttypes.h> +#include <stdatomic.h> + +#include <EGL/egl.h> + +#include <cutils/log.h> +#include <cutils/properties.h> + +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/MemoryHeapBase.h> +#include <binder/PermissionCache.h> + +#include <ui/DisplayInfo.h> +#include <ui/DisplayStatInfo.h> + +#include <gui/BitTube.h> +#include <gui/BufferQueue.h> +#include <gui/GuiConfig.h> +#include <gui/IDisplayEventConnection.h> +#include <gui/Surface.h> +#include <gui/GraphicBufferAlloc.h> + +#include <ui/GraphicBufferAllocator.h> +#include <ui/HdrCapabilities.h> +#include <ui/PixelFormat.h> +#include <ui/UiConfig.h> + +#include <utils/misc.h> +#include <utils/String8.h> +#include <utils/String16.h> +#include <utils/StopWatch.h> +#include <utils/Timers.h> +#include <utils/Trace.h> + +#include <private/android_filesystem_config.h> +#include <private/gui/SyncFeatures.h> + +#include <set> + +#include "Client.h" +#include "clz.h" +#include "Colorizer.h" +#include "DdmConnection.h" +#include "DisplayDevice.h" +#include "DispSync.h" +#include "EventControlThread.h" +#include "EventThread.h" +#include "Layer.h" +#include "LayerDim.h" +#include "SurfaceFlinger.h" + +#include "DisplayHardware/FramebufferSurface.h" +#include "DisplayHardware/HWComposer.h" +#include "DisplayHardware/VirtualDisplaySurface.h" + +#include "Effects/Daltonizer.h" + +#include "RenderEngine/RenderEngine.h" +#include <cutils/compiler.h> + +#define DISPLAY_COUNT 1 + +/* + * DEBUG_SCREENSHOTS: set to true to check that screenshots are not all + * black pixels. + */ +#define DEBUG_SCREENSHOTS false + +EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); + +// Workaround for b/30067360: /proc/self/environ inaccessible in SurfaceFlinger +// => ASan fails to read ASAN_OPTIONS => alloc-dealloc-mismatch bug is not +// suppressed and prevents the device from booting. +#ifndef __has_feature +#define __has_feature(x) 0 +#endif +#if __has_feature(address_sanitizer) +__attribute__((visibility("default"))) +extern "C" const char *__asan_default_options() { + return "alloc_dealloc_mismatch=0"; +} +#endif + +namespace android { + +// This is the phase offset in nanoseconds of the software vsync event +// relative to the vsync event reported by HWComposer. The software vsync +// event is when SurfaceFlinger and Choreographer-based applications run each +// frame. +// +// This phase offset allows adjustment of the minimum latency from application +// wake-up (by Choregographer) time to the time at which the resulting window +// image is displayed. This value may be either positive (after the HW vsync) +// or negative (before the HW vsync). Setting it to 0 will result in a +// minimum latency of two vsync periods because the app and SurfaceFlinger +// will run just after the HW vsync. Setting it to a positive number will +// result in the minimum latency being: +// +// (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD)) +// +// Note that reducing this latency makes it more likely for the applications +// to not have their window content image ready in time. When this happens +// the latency will end up being an additional vsync period, and animations +// will hiccup. Therefore, this latency should be tuned somewhat +// conservatively (or at least with awareness of the trade-off being made). +static const int64_t vsyncPhaseOffsetNs = VSYNC_EVENT_PHASE_OFFSET_NS; + +// This is the phase offset at which SurfaceFlinger's composition runs. +static const int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS; + +// --------------------------------------------------------------------------- + +const String16 sHardwareTest("android.permission.HARDWARE_TEST"); +const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); +const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); +const String16 sDump("android.permission.DUMP"); + +// --------------------------------------------------------------------------- + +SurfaceFlinger::SurfaceFlinger() + : BnSurfaceComposer(), + mTransactionFlags(0), + mTransactionPending(false), + mAnimTransactionPending(false), + mLayersRemoved(false), + mRepaintEverything(0), + mRenderEngine(NULL), + mBootTime(systemTime()), + mVisibleRegionsDirty(false), + mHwWorkListDirty(false), + mAnimCompositionPending(false), + mDebugRegion(0), + mDebugDDMS(0), + mDebugDisableHWC(0), + mDebugDisableTransformHint(0), + mDebugInSwapBuffers(0), + mLastSwapBufferTime(0), + mDebugInTransaction(0), + mLastTransactionTime(0), + mBootFinished(false), + mForceFullDamage(false), + mInterceptor(), + mPrimaryDispSync("PrimaryDispSync"), + mPrimaryHWVsyncEnabled(false), + mHWVsyncAvailable(false), + mDaltonize(false), + mHasColorMatrix(false), + mHasPoweredOff(false), + mFrameBuckets(), + mTotalTime(0), + mLastSwapTime(0) +{ + ALOGI("SurfaceFlinger is starting"); + + // debugging stuff... + char value[PROPERTY_VALUE_MAX]; + + property_get("ro.bq.gpu_to_cpu_unsupported", value, "0"); + mGpuToCpuSupported = !atoi(value); + + property_get("debug.sf.showupdates", value, "0"); + mDebugRegion = atoi(value); + + property_get("debug.sf.ddms", value, "0"); + mDebugDDMS = atoi(value); + if (mDebugDDMS) { + if (!startDdmConnection()) { + // start failed, and DDMS debugging not enabled + mDebugDDMS = 0; + } + } + ALOGI_IF(mDebugRegion, "showupdates enabled"); + ALOGI_IF(mDebugDDMS, "DDMS debugging enabled"); + + property_get("debug.sf.disable_hwc_vds", value, "0"); + mUseHwcVirtualDisplays = !atoi(value); + ALOGI_IF(!mUseHwcVirtualDisplays, "Disabling HWC virtual displays"); +} + +void SurfaceFlinger::onFirstRef() +{ + mEventQueue.init(this); +} + +SurfaceFlinger::~SurfaceFlinger() +{ + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglTerminate(display); +} + +void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */) +{ + // the window manager died on us. prepare its eulogy. + + // restore initial conditions (default device unblank, etc) + initializeDisplays(); + + // restart the boot-animation + startBootAnim(); +} + +sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() +{ + sp<ISurfaceComposerClient> bclient; + sp<Client> client(new Client(this)); + status_t err = client->initCheck(); + if (err == NO_ERROR) { + bclient = client; + } + return bclient; +} + +sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, + bool secure) +{ + class DisplayToken : public BBinder { + sp<SurfaceFlinger> flinger; + virtual ~DisplayToken() { + // no more references, this display must be terminated + Mutex::Autolock _l(flinger->mStateLock); + flinger->mCurrentState.displays.removeItem(this); + flinger->setTransactionFlags(eDisplayTransactionNeeded); + } + public: + explicit DisplayToken(const sp<SurfaceFlinger>& flinger) + : flinger(flinger) { + } + }; + + sp<BBinder> token = new DisplayToken(this); + + Mutex::Autolock _l(mStateLock); + DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure); + info.displayName = displayName; + mCurrentState.displays.add(token, info); + mInterceptor.saveDisplayCreation(info); + return token; +} + +void SurfaceFlinger::destroyDisplay(const sp<IBinder>& display) { + Mutex::Autolock _l(mStateLock); + + ssize_t idx = mCurrentState.displays.indexOfKey(display); + if (idx < 0) { + ALOGW("destroyDisplay: invalid display token"); + return; + } + + const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx)); + if (!info.isVirtualDisplay()) { + ALOGE("destroyDisplay called for non-virtual display"); + return; + } + mInterceptor.saveDisplayDeletion(info.displayId); + mCurrentState.displays.removeItemsAt(idx); + setTransactionFlags(eDisplayTransactionNeeded); +} + +void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) { + ALOGW_IF(mBuiltinDisplays[type], + "Overwriting display token for display type %d", type); + mBuiltinDisplays[type] = new BBinder(); + // All non-virtual displays are currently considered secure. + DisplayDeviceState info(type, true); + mCurrentState.displays.add(mBuiltinDisplays[type], info); + mInterceptor.saveDisplayCreation(info); +} + +sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) { + if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { + ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id); + return NULL; + } + return mBuiltinDisplays[id]; +} + +sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc() +{ + sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc()); + return gba; +} + +void SurfaceFlinger::bootFinished() +{ + const nsecs_t now = systemTime(); + const nsecs_t duration = now - mBootTime; + ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); + mBootFinished = true; + + // wait patiently for the window manager death + const String16 name("window"); + sp<IBinder> window(defaultServiceManager()->getService(name)); + if (window != 0) { + window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this)); + } + + // stop boot animation + // formerly we would just kill the process, but we now ask it to exit so it + // can choose where to stop the animation. + property_set("service.bootanim.exit", "1"); + + const int LOGTAG_SF_STOP_BOOTANIM = 60110; + LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM, + ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); +} + +void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { + class MessageDestroyGLTexture : public MessageBase { + RenderEngine& engine; + uint32_t texture; + public: + MessageDestroyGLTexture(RenderEngine& engine, uint32_t texture) + : engine(engine), texture(texture) { + } + virtual bool handler() { + engine.deleteTextures(1, &texture); + return true; + } + }; + postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture)); +} + +class DispSyncSource : public VSyncSource, private DispSync::Callback { +public: + DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, + const char* name) : + mName(name), + mValue(0), + mTraceVsync(traceVsync), + mVsyncOnLabel(String8::format("VsyncOn-%s", name)), + mVsyncEventLabel(String8::format("VSYNC-%s", name)), + mDispSync(dispSync), + mCallbackMutex(), + mCallback(), + mVsyncMutex(), + mPhaseOffset(phaseOffset), + mEnabled(false) {} + + virtual ~DispSyncSource() {} + + virtual void setVSyncEnabled(bool enable) { + Mutex::Autolock lock(mVsyncMutex); + if (enable) { + status_t err = mDispSync->addEventListener(mName, mPhaseOffset, + static_cast<DispSync::Callback*>(this)); + if (err != NO_ERROR) { + ALOGE("error registering vsync callback: %s (%d)", + strerror(-err), err); + } + //ATRACE_INT(mVsyncOnLabel.string(), 1); + } else { + status_t err = mDispSync->removeEventListener( + static_cast<DispSync::Callback*>(this)); + if (err != NO_ERROR) { + ALOGE("error unregistering vsync callback: %s (%d)", + strerror(-err), err); + } + //ATRACE_INT(mVsyncOnLabel.string(), 0); + } + mEnabled = enable; + } + + virtual void setCallback(const sp<VSyncSource::Callback>& callback) { + Mutex::Autolock lock(mCallbackMutex); + mCallback = callback; + } + + virtual void setPhaseOffset(nsecs_t phaseOffset) { + Mutex::Autolock lock(mVsyncMutex); + + // Normalize phaseOffset to [0, period) + auto period = mDispSync->getPeriod(); + phaseOffset %= period; + if (phaseOffset < 0) { + // If we're here, then phaseOffset is in (-period, 0). After this + // operation, it will be in (0, period) + phaseOffset += period; + } + mPhaseOffset = phaseOffset; + + // If we're not enabled, we don't need to mess with the listeners + if (!mEnabled) { + return; + } + + // Remove the listener with the old offset + status_t err = mDispSync->removeEventListener( + static_cast<DispSync::Callback*>(this)); + if (err != NO_ERROR) { + ALOGE("error unregistering vsync callback: %s (%d)", + strerror(-err), err); + } + + // Add a listener with the new offset + err = mDispSync->addEventListener(mName, mPhaseOffset, + static_cast<DispSync::Callback*>(this)); + if (err != NO_ERROR) { + ALOGE("error registering vsync callback: %s (%d)", + strerror(-err), err); + } + } + +private: + virtual void onDispSyncEvent(nsecs_t when) { + sp<VSyncSource::Callback> callback; + { + Mutex::Autolock lock(mCallbackMutex); + callback = mCallback; + + if (mTraceVsync) { + mValue = (mValue + 1) % 2; + ATRACE_INT(mVsyncEventLabel.string(), mValue); + } + } + + if (callback != NULL) { + callback->onVSyncEvent(when); + } + } + + const char* const mName; + + int mValue; + + const bool mTraceVsync; + const String8 mVsyncOnLabel; + const String8 mVsyncEventLabel; + + DispSync* mDispSync; + + Mutex mCallbackMutex; // Protects the following + sp<VSyncSource::Callback> mCallback; + + Mutex mVsyncMutex; // Protects the following + nsecs_t mPhaseOffset; + bool mEnabled; +}; + +class InjectVSyncSource : public VSyncSource { +public: + InjectVSyncSource() {} + + virtual ~InjectVSyncSource() {} + + virtual void setCallback(const sp<VSyncSource::Callback>& callback) { + std::lock_guard<std::mutex> lock(mCallbackMutex); + mCallback = callback; + } + + virtual void onInjectSyncEvent(nsecs_t when) { + std::lock_guard<std::mutex> lock(mCallbackMutex); + mCallback->onVSyncEvent(when); + } + + virtual void setVSyncEnabled(bool) {} + virtual void setPhaseOffset(nsecs_t) {} + +private: + std::mutex mCallbackMutex; // Protects the following + sp<VSyncSource::Callback> mCallback; +}; + +void SurfaceFlinger::init() { + ALOGI( "SurfaceFlinger's main thread ready to run. " + "Initializing graphics H/W..."); + + Mutex::Autolock _l(mStateLock); + + // initialize EGL for the default display + mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(mEGLDisplay, NULL, NULL); + + // start the EventThread + sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, + vsyncPhaseOffsetNs, true, "app"); + mEventThread = new EventThread(vsyncSrc, *this, false); + sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, + sfVsyncPhaseOffsetNs, true, "sf"); + mSFEventThread = new EventThread(sfVsyncSrc, *this, true); + mEventQueue.setEventThread(mSFEventThread); + + // set SFEventThread to SCHED_FIFO to minimize jitter + struct sched_param param = {0}; + param.sched_priority = 2; + if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, ¶m) != 0) { + ALOGE("Couldn't set SCHED_FIFO for SFEventThread"); + } + + + // Initialize the H/W composer object. There may or may not be an + // actual hardware composer underneath. + mHwc = new HWComposer(this, + *static_cast<HWComposer::EventHandler *>(this)); + + // get a RenderEngine for the given display / config (can't fail) + mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID()); + + // retrieve the EGL context that was selected/created + mEGLContext = mRenderEngine->getEGLContext(); + + LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, + "couldn't create EGLContext"); + + // initialize our non-virtual displays + for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) { + DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i); + // set-up the displays that are already connected + if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) { + // All non-virtual displays are currently considered secure. + bool isSecure = true; + createBuiltinDisplayLocked(type); + wp<IBinder> token = mBuiltinDisplays[i]; + + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer, + new GraphicBufferAlloc()); + + sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i, + consumer); + int32_t hwcId = allocateHwcDisplayId(type); + sp<DisplayDevice> hw = new DisplayDevice(this, + type, hwcId, mHwc->getFormat(hwcId), isSecure, token, + fbs, producer, + mRenderEngine->getEGLConfig()); + if (i > DisplayDevice::DISPLAY_PRIMARY) { + // FIXME: currently we don't get blank/unblank requests + // for displays other than the main display, so we always + // assume a connected display is unblanked. + ALOGD("marking display %zu as acquired/unblanked", i); + hw->setPowerMode(HWC_POWER_MODE_NORMAL); + } + mDisplays.add(token, hw); + } + } + + // make the GLContext current so that we can create textures when creating Layers + // (which may happens before we render something) + getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); + + mEventControlThread = new EventControlThread(this); + mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); + + // set a fake vsync period if there is no HWComposer + if (mHwc->initCheck() != NO_ERROR) { + mPrimaryDispSync.setPeriod(16666667); + } + + // initialize our drawing state + mDrawingState = mCurrentState; + + // set initial conditions (e.g. unblank default device) + initializeDisplays(); + + mRenderEngine->primeCache(); + + // start boot animation + startBootAnim(); +} + +int32_t SurfaceFlinger::allocateHwcDisplayId(DisplayDevice::DisplayType type) { + return (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) ? + type : mHwc->allocateDisplayId(); +} + +void SurfaceFlinger::startBootAnim() { + // start boot animation + property_set("service.bootanim.exit", "0"); + property_set("ctl.start", "bootanim"); +} + +size_t SurfaceFlinger::getMaxTextureSize() const { + return mRenderEngine->getMaxTextureSize(); +} + +size_t SurfaceFlinger::getMaxViewportDims() const { + return mRenderEngine->getMaxViewportDims(); +} + +// ---------------------------------------------------------------------------- + +bool SurfaceFlinger::authenticateSurfaceTexture( + const sp<IGraphicBufferProducer>& bufferProducer) const { + Mutex::Autolock _l(mStateLock); + sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer)); + return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0; +} + +status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display, + Vector<DisplayInfo>* configs) { + if ((configs == NULL) || (display.get() == NULL)) { + return BAD_VALUE; + } + + int32_t type = getDisplayType(display); + if (type < 0) return type; + + // TODO: Not sure if display density should handled by SF any longer + class Density { + static int getDensityFromProperty(char const* propName) { + char property[PROPERTY_VALUE_MAX]; + int density = 0; + if (property_get(propName, property, NULL) > 0) { + density = atoi(property); + } + return density; + } + public: + static int getEmuDensity() { + return getDensityFromProperty("qemu.sf.lcd_density"); } + static int getBuildDensity() { + return getDensityFromProperty("ro.sf.lcd_density"); } + }; + + configs->clear(); + + const Vector<HWComposer::DisplayConfig>& hwConfigs = + getHwComposer().getConfigs(type); + for (size_t c = 0; c < hwConfigs.size(); ++c) { + const HWComposer::DisplayConfig& hwConfig = hwConfigs[c]; + DisplayInfo info = DisplayInfo(); + + float xdpi = hwConfig.xdpi; + float ydpi = hwConfig.ydpi; + + if (type == DisplayDevice::DISPLAY_PRIMARY) { + // The density of the device is provided by a build property + float density = Density::getBuildDensity() / 160.0f; + if (density == 0) { + // the build doesn't provide a density -- this is wrong! + // use xdpi instead + ALOGE("ro.sf.lcd_density must be defined as a build property"); + density = xdpi / 160.0f; + } + if (Density::getEmuDensity()) { + // if "qemu.sf.lcd_density" is specified, it overrides everything + xdpi = ydpi = density = Density::getEmuDensity(); + density /= 160.0f; + } + info.density = density; + + // TODO: this needs to go away (currently needed only by webkit) + sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + info.orientation = hw->getOrientation(); + } else { + // TODO: where should this value come from? + static const int TV_DENSITY = 213; + info.density = TV_DENSITY / 160.0f; + info.orientation = 0; + } + + info.w = hwConfig.width; + info.h = hwConfig.height; + info.xdpi = xdpi; + info.ydpi = ydpi; + info.fps = float(1e9 / hwConfig.refresh); + info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS; + + // This is how far in advance a buffer must be queued for + // presentation at a given time. If you want a buffer to appear + // on the screen at time N, you must submit the buffer before + // (N - presentationDeadline). + // + // Normally it's one full refresh period (to give SF a chance to + // latch the buffer), but this can be reduced by configuring a + // DispSync offset. Any additional delays introduced by the hardware + // composer or panel must be accounted for here. + // + // We add an additional 1ms to allow for processing time and + // differences between the ideal and actual refresh rate. + info.presentationDeadline = + hwConfig.refresh - SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000; + + // All non-virtual displays are currently considered secure. + info.secure = true; + + configs->push_back(info); + } + + return NO_ERROR; +} + +status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */, + DisplayStatInfo* stats) { + if (stats == NULL) { + return BAD_VALUE; + } + + // FIXME for now we always return stats for the primary display + memset(stats, 0, sizeof(*stats)); + stats->vsyncTime = mPrimaryDispSync.computeNextRefresh(0); + stats->vsyncPeriod = mPrimaryDispSync.getPeriod(); + return NO_ERROR; +} + +int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) { + sp<DisplayDevice> device(getDisplayDevice(display)); + if (device != NULL) { + return device->getActiveConfig(); + } + return BAD_VALUE; +} + +void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode) { + ALOGD("Set active config mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(), + this); + int32_t type = hw->getDisplayType(); + int currentMode = hw->getActiveConfig(); + + if (mode == currentMode) { + ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode); + return; + } + + if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { + ALOGW("Trying to set config for virtual display"); + return; + } + + hw->setActiveConfig(mode); + getHwComposer().setActiveConfig(type, mode); +} + +status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) { + class MessageSetActiveConfig: public MessageBase { + SurfaceFlinger& mFlinger; + sp<IBinder> mDisplay; + int mMode; + public: + MessageSetActiveConfig(SurfaceFlinger& flinger, const sp<IBinder>& disp, + int mode) : + mFlinger(flinger), mDisplay(disp) { mMode = mode; } + virtual bool handler() { + Vector<DisplayInfo> configs; + mFlinger.getDisplayConfigs(mDisplay, &configs); + if (mMode < 0 || mMode >= static_cast<int>(configs.size())) { + ALOGE("Attempt to set active config = %d for display with %zu configs", + mMode, configs.size()); + } + sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay)); + if (hw == NULL) { + ALOGE("Attempt to set active config = %d for null display %p", + mMode, mDisplay.get()); + } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) { + ALOGW("Attempt to set active config = %d for virtual display", + mMode); + } else { + mFlinger.setActiveConfigInternal(hw, mMode); + } + return true; + } + }; + sp<MessageBase> msg = new MessageSetActiveConfig(*this, display, mode); + postMessageSync(msg); + return NO_ERROR; +} + +status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display, + Vector<android_color_mode_t>* outColorModes) { + if (outColorModes == nullptr || display.get() == nullptr) { + return BAD_VALUE; + } + + int32_t type = getDisplayType(display); + if (type < 0) return type; + + std::set<android_color_mode_t> colorModes; + for (const HWComposer::DisplayConfig& hwConfig : getHwComposer().getConfigs(type)) { + colorModes.insert(hwConfig.colorMode); + } + + outColorModes->clear(); + std::copy(colorModes.cbegin(), colorModes.cend(), std::back_inserter(*outColorModes)); + + return NO_ERROR; +} + +android_color_mode_t SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) { + if (display.get() == nullptr) return static_cast<android_color_mode_t>(BAD_VALUE); + + int32_t type = getDisplayType(display); + if (type < 0) return static_cast<android_color_mode_t>(type); + + return getHwComposer().getColorMode(type); +} + +status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display, + android_color_mode_t colorMode) { + if (display.get() == nullptr || colorMode < 0) { + return BAD_VALUE; + } + + int32_t type = getDisplayType(display); + if (type < 0) return type; + const Vector<HWComposer::DisplayConfig>& hwConfigs = getHwComposer().getConfigs(type); + HWComposer::DisplayConfig desiredConfig = hwConfigs[getHwComposer().getCurrentConfig(type)]; + desiredConfig.colorMode = colorMode; + for (size_t c = 0; c < hwConfigs.size(); ++c) { + const HWComposer::DisplayConfig config = hwConfigs[c]; + if (config == desiredConfig) { + return setActiveConfig(display, c); + } + } + return BAD_VALUE; +} + +status_t SurfaceFlinger::clearAnimationFrameStats() { + Mutex::Autolock _l(mStateLock); + mAnimFrameTracker.clearStats(); + return NO_ERROR; +} + +status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const { + Mutex::Autolock _l(mStateLock); + mAnimFrameTracker.getStats(outStats); + return NO_ERROR; +} + +status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& /*display*/, + HdrCapabilities* outCapabilities) const { + // HWC1 does not provide HDR capabilities + *outCapabilities = HdrCapabilities(); + return NO_ERROR; +} + +status_t SurfaceFlinger::enableVSyncInjections(bool enable) { + if (enable == mInjectVSyncs) { + return NO_ERROR; + } + + if (enable) { + mInjectVSyncs = enable; + ALOGV("VSync Injections enabled"); + if (mVSyncInjector.get() == nullptr) { + mVSyncInjector = new InjectVSyncSource(); + mInjectorEventThread = new EventThread(mVSyncInjector, *this, false); + } + mEventQueue.setEventThread(mInjectorEventThread); + } else { + mInjectVSyncs = enable; + ALOGV("VSync Injections disabled"); + mEventQueue.setEventThread(mSFEventThread); + mVSyncInjector.clear(); + } + return NO_ERROR; +} + +status_t SurfaceFlinger::injectVSync(nsecs_t when) { + if (!mInjectVSyncs) { + ALOGE("VSync Injections not enabled"); + return BAD_VALUE; + } + if (mInjectVSyncs && mInjectorEventThread.get() != nullptr) { + ALOGV("Injecting VSync inside SurfaceFlinger"); + mVSyncInjector->onInjectSyncEvent(when); + } + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- + +sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() { + return mEventThread->createEventConnection(); +} + +// ---------------------------------------------------------------------------- + +void SurfaceFlinger::waitForEvent() { + mEventQueue.waitMessage(); +} + +void SurfaceFlinger::signalTransaction() { + mEventQueue.invalidate(); +} + +void SurfaceFlinger::signalLayerUpdate() { + mEventQueue.invalidate(); +} + +void SurfaceFlinger::signalRefresh() { + mEventQueue.refresh(); +} + +status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg, + nsecs_t reltime, uint32_t /* flags */) { + return mEventQueue.postMessage(msg, reltime); +} + +status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg, + nsecs_t reltime, uint32_t /* flags */) { + status_t res = mEventQueue.postMessage(msg, reltime); + if (res == NO_ERROR) { + msg->wait(); + } + return res; +} + +void SurfaceFlinger::run() { + do { + waitForEvent(); + } while (true); +} + +void SurfaceFlinger::enableHardwareVsync() { + Mutex::Autolock _l(mHWVsyncLock); + if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { + mPrimaryDispSync.beginResync(); + //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); + mEventControlThread->setVsyncEnabled(true); + mPrimaryHWVsyncEnabled = true; + } +} + +void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) { + Mutex::Autolock _l(mHWVsyncLock); + + if (makeAvailable) { + mHWVsyncAvailable = true; + } else if (!mHWVsyncAvailable) { + // Hardware vsync is not currently available, so abort the resync + // attempt for now + return; + } + + const nsecs_t period = + getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); + + mPrimaryDispSync.reset(); + mPrimaryDispSync.setPeriod(period); + + if (!mPrimaryHWVsyncEnabled) { + mPrimaryDispSync.beginResync(); + //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); + mEventControlThread->setVsyncEnabled(true); + mPrimaryHWVsyncEnabled = true; + } +} + +void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) { + Mutex::Autolock _l(mHWVsyncLock); + if (mPrimaryHWVsyncEnabled) { + //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false); + mEventControlThread->setVsyncEnabled(false); + mPrimaryDispSync.endResync(); + mPrimaryHWVsyncEnabled = false; + } + if (makeUnavailable) { + mHWVsyncAvailable = false; + } +} + +void SurfaceFlinger::resyncWithRateLimit() { + static constexpr nsecs_t kIgnoreDelay = ms2ns(500); + if (systemTime() - mLastSwapTime > kIgnoreDelay) { + resyncToHardwareVsync(false); + } +} + +void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) { + bool needsHwVsync = false; + + { // Scope for the lock + Mutex::Autolock _l(mHWVsyncLock); + if (type == 0 && mPrimaryHWVsyncEnabled) { + needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp); + } + } + + if (needsHwVsync) { + enableHardwareVsync(); + } else { + disableHardwareVsync(false); + } +} + +void SurfaceFlinger::onHotplugReceived(int type, bool connected) { + if (mEventThread == NULL) { + // This is a temporary workaround for b/7145521. A non-null pointer + // does not mean EventThread has finished initializing, so this + // is not a correct fix. + ALOGW("WARNING: EventThread not started, ignoring hotplug"); + return; + } + + if (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { + Mutex::Autolock _l(mStateLock); + if (connected) { + createBuiltinDisplayLocked((DisplayDevice::DisplayType)type); + } else { + mCurrentState.displays.removeItem(mBuiltinDisplays[type]); + mBuiltinDisplays[type].clear(); + } + setTransactionFlags(eDisplayTransactionNeeded); + + // Defer EventThread notification until SF has updated mDisplays. + } +} + +void SurfaceFlinger::eventControl(int disp, int event, int enabled) { + ATRACE_CALL(); + getHwComposer().eventControl(disp, event, enabled); +} + +void SurfaceFlinger::onMessageReceived(int32_t what) { + ATRACE_CALL(); + switch (what) { + case MessageQueue::INVALIDATE: { + bool refreshNeeded = handleMessageTransaction(); + refreshNeeded |= handleMessageInvalidate(); + refreshNeeded |= mRepaintEverything; + if (refreshNeeded) { + // Signal a refresh if a transaction modified the window state, + // a new buffer was latched, or if HWC has requested a full + // repaint + signalRefresh(); + } + break; + } + case MessageQueue::REFRESH: { + handleMessageRefresh(); + break; + } + } +} + +bool SurfaceFlinger::handleMessageTransaction() { + uint32_t transactionFlags = peekTransactionFlags(eTransactionMask); + if (transactionFlags) { + handleTransaction(transactionFlags); + return true; + } + return false; +} + +bool SurfaceFlinger::handleMessageInvalidate() { + ATRACE_CALL(); + return handlePageFlip(); +} + +void SurfaceFlinger::handleMessageRefresh() { + ATRACE_CALL(); + + nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + + preComposition(); + rebuildLayerStacks(); + setUpHWComposer(); + doDebugFlashRegions(); + doComposition(); + postComposition(refreshStartTime); +} + +void SurfaceFlinger::doDebugFlashRegions() +{ + // is debugging enabled + if (CC_LIKELY(!mDebugRegion)) + return; + + const bool repaintEverything = mRepaintEverything; + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + const sp<DisplayDevice>& hw(mDisplays[dpy]); + if (hw->isDisplayOn()) { + // transform the dirty region into this screen's coordinate space + const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); + if (!dirtyRegion.isEmpty()) { + // redraw the whole screen + doComposeSurfaces(hw, Region(hw->bounds())); + + // and draw the dirty region + const int32_t height = hw->getHeight(); + RenderEngine& engine(getRenderEngine()); + engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1); + + hw->compositionComplete(); + hw->swapBuffers(getHwComposer()); + } + } + } + + postFramebuffer(); + + if (mDebugRegion > 1) { + usleep(mDebugRegion * 1000); + } + + HWComposer& hwc(getHwComposer()); + if (hwc.initCheck() == NO_ERROR) { + status_t err = hwc.prepare(); + ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); + } +} + +void SurfaceFlinger::preComposition() +{ + bool needExtraInvalidate = false; + const LayerVector& layers(mDrawingState.layersSortedByZ); + const size_t count = layers.size(); + for (size_t i=0 ; i<count ; i++) { + if (layers[i]->onPreComposition()) { + needExtraInvalidate = true; + } + } + if (needExtraInvalidate) { + signalLayerUpdate(); + } +} + +void SurfaceFlinger::postComposition(nsecs_t refreshStartTime) +{ + const LayerVector& layers(mDrawingState.layersSortedByZ); + const size_t count = layers.size(); + for (size_t i=0 ; i<count ; i++) { + bool frameLatched = layers[i]->onPostComposition(); + if (frameLatched) { + recordBufferingStats(layers[i]->getName().string(), + layers[i]->getOccupancyHistory(false)); + } + } + + const HWComposer& hwc = getHwComposer(); + sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY); + + if (presentFence->isValid()) { + if (mPrimaryDispSync.addPresentFence(presentFence)) { + enableHardwareVsync(); + } else { + disableHardwareVsync(false); + } + } + + const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + if (kIgnorePresentFences) { + if (hw->isDisplayOn()) { + enableHardwareVsync(); + } + } + + mFenceTracker.addFrame(refreshStartTime, presentFence, + hw->getVisibleLayersSortedByZ(), hw->getClientTargetAcquireFence()); + + if (mAnimCompositionPending) { + mAnimCompositionPending = false; + + if (presentFence->isValid()) { + mAnimFrameTracker.setActualPresentFence(presentFence); + } else { + // The HWC doesn't support present fences, so use the refresh + // timestamp instead. + nsecs_t presentTime = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY); + mAnimFrameTracker.setActualPresentTime(presentTime); + } + 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() { + // rebuild the visible layer list per screen + if (CC_UNLIKELY(mVisibleRegionsDirty)) { + ATRACE_CALL(); + mVisibleRegionsDirty = false; + invalidateHwcGeometry(); + + const LayerVector& layers(mDrawingState.layersSortedByZ); + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + Region opaqueRegion; + Region dirtyRegion; + Vector< sp<Layer> > layersSortedByZ; + const sp<DisplayDevice>& hw(mDisplays[dpy]); + const Transform& tr(hw->getTransform()); + const Rect bounds(hw->getBounds()); + if (hw->isDisplayOn()) { + SurfaceFlinger::computeVisibleRegions(layers, + hw->getLayerStack(), dirtyRegion, opaqueRegion); + + const size_t count = layers.size(); + for (size_t i=0 ; i<count ; i++) { + const sp<Layer>& layer(layers[i]); + const Layer::State& s(layer->getDrawingState()); + if (s.layerStack == hw->getLayerStack()) { + Region drawRegion(tr.transform( + layer->visibleNonTransparentRegion)); + drawRegion.andSelf(bounds); + if (!drawRegion.isEmpty()) { + layersSortedByZ.add(layer); + } + } + } + } + hw->setVisibleLayersSortedByZ(layersSortedByZ); + hw->undefinedRegion.set(bounds); + hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion)); + hw->dirtyRegion.orSelf(dirtyRegion); + } + } +} + +void SurfaceFlinger::setUpHWComposer() { + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty(); + bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0; + bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers; + + // If nothing has changed (!dirty), don't recompose. + // If something changed, but we don't currently have any visible layers, + // and didn't when we last did a composition, then skip it this time. + // The second rule does two things: + // - When all layers are removed from a display, we'll emit one black + // frame, then nothing more until we get new layers. + // - When a display is created with a private layer stack, we won't + // emit any black frames until a layer is added to the layer stack. + bool mustRecompose = dirty && !(empty && wasEmpty); + + ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL, + "dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy, + mustRecompose ? "doing" : "skipping", + dirty ? "+" : "-", + empty ? "+" : "-", + wasEmpty ? "+" : "-"); + + mDisplays[dpy]->beginFrame(mustRecompose); + + if (mustRecompose) { + mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty; + } + } + + HWComposer& hwc(getHwComposer()); + if (hwc.initCheck() == NO_ERROR) { + // build the h/w work list + if (CC_UNLIKELY(mHwWorkListDirty)) { + mHwWorkListDirty = false; + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + sp<const DisplayDevice> hw(mDisplays[dpy]); + const int32_t id = hw->getHwcDisplayId(); + if (id >= 0) { + const Vector< sp<Layer> >& currentLayers( + hw->getVisibleLayersSortedByZ()); + const size_t count = currentLayers.size(); + if (hwc.createWorkList(id, count) == NO_ERROR) { + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); + for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { + const sp<Layer>& layer(currentLayers[i]); + layer->setGeometry(hw, *cur); + if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) { + cur->setSkip(true); + } + } + } + } + } + } + + // set the per-frame data + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + sp<const DisplayDevice> hw(mDisplays[dpy]); + const int32_t id = hw->getHwcDisplayId(); + if (id >= 0) { + const Vector< sp<Layer> >& currentLayers( + hw->getVisibleLayersSortedByZ()); + const size_t count = currentLayers.size(); + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); + for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { + /* + * update the per-frame h/w composer data for each layer + * and build the transparent region of the FB + */ + const sp<Layer>& layer(currentLayers[i]); + layer->setPerFrameData(hw, *cur); + } + } + } + + // If possible, attempt to use the cursor overlay on each display. + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + sp<const DisplayDevice> hw(mDisplays[dpy]); + const int32_t id = hw->getHwcDisplayId(); + if (id >= 0) { + const Vector< sp<Layer> >& currentLayers( + hw->getVisibleLayersSortedByZ()); + const size_t count = currentLayers.size(); + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); + for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { + const sp<Layer>& layer(currentLayers[i]); + if (layer->isPotentialCursor()) { + cur->setIsCursorLayerHint(); + break; + } + } + } + } + + status_t err = hwc.prepare(); + ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); + + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + sp<const DisplayDevice> hw(mDisplays[dpy]); + hw->prepareFrame(hwc); + } + } +} + +void SurfaceFlinger::doComposition() { + ATRACE_CALL(); + const bool repaintEverything = android_atomic_and(0, &mRepaintEverything); + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + const sp<DisplayDevice>& hw(mDisplays[dpy]); + if (hw->isDisplayOn()) { + // transform the dirty region into this screen's coordinate space + const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); + + // repaint the framebuffer (if needed) + doDisplayComposition(hw, dirtyRegion); + + hw->dirtyRegion.clear(); + hw->flip(hw->swapRegion); + hw->swapRegion.clear(); + } + // inform the h/w that we're done compositing + hw->compositionComplete(); + } + postFramebuffer(); +} + +void SurfaceFlinger::postFramebuffer() +{ + ATRACE_CALL(); + + const nsecs_t now = systemTime(); + mDebugInSwapBuffers = now; + + HWComposer& hwc(getHwComposer()); + if (hwc.initCheck() == NO_ERROR) { + if (!hwc.supportsFramebufferTarget()) { + // EGL spec says: + // "surface must be bound to the calling thread's current context, + // for the current rendering API." + getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); + } + hwc.commit(); + } + + // make the default display current because the VirtualDisplayDevice code cannot + // deal with dequeueBuffer() being called outside of the composition loop; however + // the code below can call glFlush() which is allowed (and does in some case) call + // dequeueBuffer(). + getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); + + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + sp<const DisplayDevice> hw(mDisplays[dpy]); + const Vector< sp<Layer> >& currentLayers(hw->getVisibleLayersSortedByZ()); + hw->onSwapBuffersCompleted(hwc); + const size_t count = currentLayers.size(); + int32_t id = hw->getHwcDisplayId(); + if (id >=0 && hwc.initCheck() == NO_ERROR) { + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); + for (size_t i = 0; cur != end && i < count; ++i, ++cur) { + currentLayers[i]->onLayerDisplayed(hw, &*cur); + } + } else { + for (size_t i = 0; i < count; i++) { + currentLayers[i]->onLayerDisplayed(hw, NULL); + } + } + } + + mLastSwapBufferTime = systemTime() - now; + mDebugInSwapBuffers = 0; + + uint32_t flipCount = getDefaultDisplayDevice()->getPageFlipCount(); + if (flipCount % LOG_FRAME_STATS_PERIOD == 0) { + logFrameStats(); + } +} + +void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) +{ + ATRACE_CALL(); + + // here we keep a copy of the drawing state (that is the state that's + // going to be overwritten by handleTransactionLocked()) outside of + // mStateLock so that the side-effects of the State assignment + // don't happen with mStateLock held (which can cause deadlocks). + State drawingState(mDrawingState); + + Mutex::Autolock _l(mStateLock); + const nsecs_t now = systemTime(); + mDebugInTransaction = now; + + // Here we're guaranteed that some transaction flags are set + // so we can call handleTransactionLocked() unconditionally. + // We call getTransactionFlags(), which will also clear the flags, + // with mStateLock held to guarantee that mCurrentState won't change + // until the transaction is committed. + + transactionFlags = getTransactionFlags(eTransactionMask); + handleTransactionLocked(transactionFlags); + + mLastTransactionTime = systemTime() - now; + mDebugInTransaction = 0; + invalidateHwcGeometry(); + // here the transaction has been committed +} + +void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) +{ + const LayerVector& currentLayers(mCurrentState.layersSortedByZ); + const size_t count = currentLayers.size(); + + // Notify all layers of available frames + for (size_t i = 0; i < count; ++i) { + currentLayers[i]->notifyAvailableFrames(); + } + + /* + * Traversal of the children + * (perform the transaction for each of them if needed) + */ + + if (transactionFlags & eTraversalNeeded) { + for (size_t i=0 ; i<count ; i++) { + const sp<Layer>& layer(currentLayers[i]); + uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); + if (!trFlags) continue; + + const uint32_t flags = layer->doTransaction(0); + if (flags & Layer::eVisibleRegion) + mVisibleRegionsDirty = true; + } + } + + /* + * Perform display own transactions if needed + */ + + if (transactionFlags & eDisplayTransactionNeeded) { + // here we take advantage of Vector's copy-on-write semantics to + // improve performance by skipping the transaction entirely when + // know that the lists are identical + const KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays); + const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays); + if (!curr.isIdenticalTo(draw)) { + mVisibleRegionsDirty = true; + const size_t cc = curr.size(); + size_t dc = draw.size(); + + // find the displays that were removed + // (ie: in drawing state but not in current state) + // also handle displays that changed + // (ie: displays that are in both lists) + for (size_t i=0 ; i<dc ; i++) { + const ssize_t j = curr.indexOfKey(draw.keyAt(i)); + if (j < 0) { + // in drawing state but not in current state + if (!draw[i].isMainDisplay()) { + // Call makeCurrent() on the primary display so we can + // be sure that nothing associated with this display + // is current. + const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDevice()); + defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext); + sp<DisplayDevice> hw(getDisplayDevice(draw.keyAt(i))); + if (hw != NULL) + hw->disconnect(getHwComposer()); + if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) + mEventThread->onHotplugReceived(draw[i].type, false); + mDisplays.removeItem(draw.keyAt(i)); + } else { + ALOGW("trying to remove the main display"); + } + } else { + // this display is in both lists. see if something changed. + const DisplayDeviceState& state(curr[j]); + const wp<IBinder>& display(curr.keyAt(j)); + const sp<IBinder> state_binder = IInterface::asBinder(state.surface); + const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface); + if (state_binder != draw_binder) { + // changing the surface is like destroying and + // recreating the DisplayDevice, so we just remove it + // from the drawing state, so that it get re-added + // below. + sp<DisplayDevice> hw(getDisplayDevice(display)); + if (hw != NULL) + hw->disconnect(getHwComposer()); + mDisplays.removeItem(display); + mDrawingState.displays.removeItemsAt(i); + dc--; i--; + // at this point we must loop to the next item + continue; + } + + const sp<DisplayDevice> disp(getDisplayDevice(display)); + if (disp != NULL) { + if (state.layerStack != draw[i].layerStack) { + disp->setLayerStack(state.layerStack); + } + if ((state.orientation != draw[i].orientation) + || (state.viewport != draw[i].viewport) + || (state.frame != draw[i].frame)) + { + disp->setProjection(state.orientation, + state.viewport, state.frame); + } + if (state.width != draw[i].width || state.height != draw[i].height) { + disp->setDisplaySize(state.width, state.height); + } + } + } + } + + // find displays that were added + // (ie: in current state but not in drawing state) + for (size_t i=0 ; i<cc ; i++) { + if (draw.indexOfKey(curr.keyAt(i)) < 0) { + const DisplayDeviceState& state(curr[i]); + + sp<DisplaySurface> dispSurface; + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferProducer> bqProducer; + sp<IGraphicBufferConsumer> bqConsumer; + BufferQueue::createBufferQueue(&bqProducer, &bqConsumer, + new GraphicBufferAlloc()); + + int32_t hwcDisplayId = -1; + if (state.isVirtualDisplay()) { + // Virtual displays without a surface are dormant: + // they have external state (layer stack, projection, + // etc.) but no internal state (i.e. a DisplayDevice). + if (state.surface != NULL) { + + int width = 0; + int status = state.surface->query( + NATIVE_WINDOW_WIDTH, &width); + ALOGE_IF(status != NO_ERROR, + "Unable to query width (%d)", status); + int height = 0; + status = state.surface->query( + NATIVE_WINDOW_HEIGHT, &height); + ALOGE_IF(status != NO_ERROR, + "Unable to query height (%d)", status); + if (mUseHwcVirtualDisplays && + (MAX_VIRTUAL_DISPLAY_DIMENSION == 0 || + (width <= MAX_VIRTUAL_DISPLAY_DIMENSION && + height <= MAX_VIRTUAL_DISPLAY_DIMENSION))) { + hwcDisplayId = allocateHwcDisplayId(state.type); + } + + sp<VirtualDisplaySurface> vds = new VirtualDisplaySurface( + *mHwc, hwcDisplayId, state.surface, + bqProducer, bqConsumer, state.displayName); + + dispSurface = vds; + producer = vds; + } + } else { + ALOGE_IF(state.surface!=NULL, + "adding a supported display, but rendering " + "surface is provided (%p), ignoring it", + state.surface.get()); + hwcDisplayId = allocateHwcDisplayId(state.type); + // for supported (by hwc) displays we provide our + // own rendering surface + dispSurface = new FramebufferSurface(*mHwc, state.type, + bqConsumer); + producer = bqProducer; + } + + const wp<IBinder>& display(curr.keyAt(i)); + if (dispSurface != NULL) { + sp<DisplayDevice> hw = new DisplayDevice(this, + state.type, hwcDisplayId, + mHwc->getFormat(hwcDisplayId), state.isSecure, + display, dispSurface, producer, + mRenderEngine->getEGLConfig()); + hw->setLayerStack(state.layerStack); + hw->setProjection(state.orientation, + state.viewport, state.frame); + hw->setDisplayName(state.displayName); + mDisplays.add(display, hw); + if (state.isVirtualDisplay()) { + if (hwcDisplayId >= 0) { + mHwc->setVirtualDisplayProperties(hwcDisplayId, + hw->getWidth(), hw->getHeight(), + hw->getFormat()); + } + } else { + mEventThread->onHotplugReceived(state.type, true); + } + } + } + } + } + } + + if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) { + // The transform hint might have changed for some layers + // (either because a display has changed, or because a layer + // as changed). + // + // Walk through all the layers in currentLayers, + // and update their transform hint. + // + // If a layer is visible only on a single display, then that + // display is used to calculate the hint, otherwise we use the + // default display. + // + // NOTE: we do this here, rather than in rebuildLayerStacks() so that + // the hint is set before we acquire a buffer from the surface texture. + // + // NOTE: layer transactions have taken place already, so we use their + // drawing state. However, SurfaceFlinger's own transaction has not + // happened yet, so we must use the current state layer list + // (soon to become the drawing state list). + // + sp<const DisplayDevice> disp; + uint32_t currentlayerStack = 0; + for (size_t i=0; i<count; i++) { + // NOTE: we rely on the fact that layers are sorted by + // layerStack first (so we don't have to traverse the list + // of displays for every layer). + const sp<Layer>& layer(currentLayers[i]); + uint32_t layerStack = layer->getDrawingState().layerStack; + if (i==0 || currentlayerStack != layerStack) { + currentlayerStack = layerStack; + // figure out if this layerstack is mirrored + // (more than one display) if so, pick the default display, + // if not, pick the only display it's on. + disp.clear(); + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + sp<const DisplayDevice> hw(mDisplays[dpy]); + if (hw->getLayerStack() == currentlayerStack) { + if (disp == NULL) { + disp = hw; + } else { + disp = NULL; + break; + } + } + } + } + if (disp == NULL) { + // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to + // redraw after transform hint changes. See bug 8508397. + + // could be null when this layer is using a layerStack + // that is not visible on any display. Also can occur at + // screen off/on times. + disp = getDefaultDisplayDevice(); + } + layer->updateTransformHint(disp); + } + } + + + /* + * Perform our own transaction if needed + */ + + const LayerVector& layers(mDrawingState.layersSortedByZ); + if (currentLayers.size() > layers.size()) { + // layers have been added + mVisibleRegionsDirty = true; + } + + // some layers might have been removed, so + // we need to update the regions they're exposing. + if (mLayersRemoved) { + mLayersRemoved = false; + mVisibleRegionsDirty = true; + const size_t count = layers.size(); + for (size_t i=0 ; i<count ; i++) { + const sp<Layer>& layer(layers[i]); + if (currentLayers.indexOf(layer) < 0) { + // this layer is not visible anymore + // TODO: we could traverse the tree from front to back and + // compute the actual visible region + // TODO: we could cache the transformed region + const Layer::State& s(layer->getDrawingState()); + Region visibleReg = s.active.transform.transform( + Region(Rect(s.active.w, s.active.h))); + invalidateLayerStack(s.layerStack, visibleReg); + } + } + } + + commitTransaction(); + + updateCursorAsync(); +} + +void SurfaceFlinger::updateCursorAsync() +{ + HWComposer& hwc(getHwComposer()); + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + sp<const DisplayDevice> hw(mDisplays[dpy]); + const int32_t id = hw->getHwcDisplayId(); + if (id < 0) { + continue; + } + const Vector< sp<Layer> >& currentLayers( + hw->getVisibleLayersSortedByZ()); + const size_t count = currentLayers.size(); + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); + for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) { + if (cur->getCompositionType() != HWC_CURSOR_OVERLAY) { + continue; + } + const sp<Layer>& layer(currentLayers[i]); + Rect cursorPos = layer->getPosition(hw); + hwc.setCursorPositionAsync(id, cursorPos); + break; + } + } +} + +void SurfaceFlinger::commitTransaction() +{ + if (!mLayersPendingRemoval.isEmpty()) { + // Notify removed layers now that they can't be drawn from + for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) { + recordBufferingStats(mLayersPendingRemoval[i]->getName().string(), + mLayersPendingRemoval[i]->getOccupancyHistory(true)); + mLayersPendingRemoval[i]->onRemoved(); + } + mLayersPendingRemoval.clear(); + } + + // If this transaction is part of a window animation then the next frame + // we composite should be considered an animation as well. + mAnimCompositionPending = mAnimTransactionPending; + + mDrawingState = mCurrentState; + mTransactionPending = false; + mAnimTransactionPending = false; + mTransactionCV.broadcast(); +} + +void SurfaceFlinger::computeVisibleRegions( + const LayerVector& currentLayers, uint32_t layerStack, + Region& outDirtyRegion, Region& outOpaqueRegion) +{ + ATRACE_CALL(); + + Region aboveOpaqueLayers; + Region aboveCoveredLayers; + Region dirty; + + outDirtyRegion.clear(); + + size_t i = currentLayers.size(); + while (i--) { + const sp<Layer>& layer = currentLayers[i]; + + // start with the whole surface at its current location + const Layer::State& s(layer->getDrawingState()); + + // only consider the layers on the given layer stack + if (s.layerStack != layerStack) + continue; + + /* + * opaqueRegion: area of a surface that is fully opaque. + */ + Region opaqueRegion; + + /* + * visibleRegion: area of a surface that is visible on screen + * and not fully transparent. This is essentially the layer's + * footprint minus the opaque regions above it. + * Areas covered by a translucent surface are considered visible. + */ + Region visibleRegion; + + /* + * coveredRegion: area of a surface that is covered by all + * visible regions above it (which includes the translucent areas). + */ + Region coveredRegion; + + /* + * transparentRegion: area of a surface that is hinted to be completely + * transparent. This is only used to tell when the layer has no visible + * non-transparent regions and can be removed from the layer list. It + * does not affect the visibleRegion of this layer or any layers + * beneath it. The hint may not be correct if apps don't respect the + * SurfaceView restrictions (which, sadly, some don't). + */ + Region transparentRegion; + + + // handle hidden surfaces by setting the visible region to empty + if (CC_LIKELY(layer->isVisible())) { + const bool translucent = !layer->isOpaque(s); + Rect bounds(s.active.transform.transform(layer->computeBounds())); + visibleRegion.set(bounds); + if (!visibleRegion.isEmpty()) { + // Remove the transparent area from the visible region + if (translucent) { + const Transform tr(s.active.transform); + if (tr.preserveRects()) { + // transform the transparent region + transparentRegion = tr.transform(s.activeTransparentRegion); + } else { + // transformation too complex, can't do the + // transparent region optimization. + transparentRegion.clear(); + } + } + + // compute the opaque region + const int32_t layerOrientation = s.active.transform.getOrientation(); + if (s.alpha==255 && !translucent && + ((layerOrientation & Transform::ROT_INVALID) == false)) { + // the opaque region is the layer's footprint + opaqueRegion = visibleRegion; + } + } + } + + // Clip the covered region to the visible region + coveredRegion = aboveCoveredLayers.intersect(visibleRegion); + + // Update aboveCoveredLayers for next (lower) layer + aboveCoveredLayers.orSelf(visibleRegion); + + // subtract the opaque region covered by the layers above us + visibleRegion.subtractSelf(aboveOpaqueLayers); + + // compute this layer's dirty region + if (layer->contentDirty) { + // we need to invalidate the whole region + dirty = visibleRegion; + // as well, as the old visible region + dirty.orSelf(layer->visibleRegion); + layer->contentDirty = false; + } else { + /* compute the exposed region: + * the exposed region consists of two components: + * 1) what's VISIBLE now and was COVERED before + * 2) what's EXPOSED now less what was EXPOSED before + * + * note that (1) is conservative, we start with the whole + * visible region but only keep what used to be covered by + * something -- which mean it may have been exposed. + * + * (2) handles areas that were not covered by anything but got + * exposed because of a resize. + */ + const Region newExposed = visibleRegion - coveredRegion; + const Region oldVisibleRegion = layer->visibleRegion; + const Region oldCoveredRegion = layer->coveredRegion; + const Region oldExposed = oldVisibleRegion - oldCoveredRegion; + dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed); + } + dirty.subtractSelf(aboveOpaqueLayers); + + // accumulate to the screen dirty region + outDirtyRegion.orSelf(dirty); + + // Update aboveOpaqueLayers for next (lower) layer + aboveOpaqueLayers.orSelf(opaqueRegion); + + // Store the visible region in screen space + layer->setVisibleRegion(visibleRegion); + layer->setCoveredRegion(coveredRegion); + layer->setVisibleNonTransparentRegion( + visibleRegion.subtract(transparentRegion)); + } + + outOpaqueRegion = aboveOpaqueLayers; +} + +void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack, + const Region& dirty) { + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + const sp<DisplayDevice>& hw(mDisplays[dpy]); + if (hw->getLayerStack() == layerStack) { + hw->dirtyRegion.orSelf(dirty); + } + } +} + +bool SurfaceFlinger::handlePageFlip() +{ + Region dirtyRegion; + + bool visibleRegions = false; + const LayerVector& layers(mDrawingState.layersSortedByZ); + bool frameQueued = false; + + // Store the set of layers that need updates. This set must not change as + // buffers are being latched, as this could result in a deadlock. + // Example: Two producers share the same command stream and: + // 1.) Layer 0 is latched + // 2.) Layer 0 gets a new frame + // 2.) Layer 1 gets a new frame + // 3.) Layer 1 is latched. + // Display is now waiting on Layer 1's frame, which is behind layer 0's + // second frame. But layer 0's second frame could be waiting on display. + Vector<Layer*> layersWithQueuedFrames; + for (size_t i = 0, count = layers.size(); i<count ; i++) { + const sp<Layer>& layer(layers[i]); + if (layer->hasQueuedFrame()) { + frameQueued = true; + if (layer->shouldPresentNow(mPrimaryDispSync)) { + layersWithQueuedFrames.push_back(layer.get()); + } else { + layer->useEmptyDamage(); + } + } else { + layer->useEmptyDamage(); + } + } + for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) { + Layer* layer = layersWithQueuedFrames[i]; + const Region dirty(layer->latchBuffer(visibleRegions)); + layer->useSurfaceDamage(); + const Layer::State& s(layer->getDrawingState()); + invalidateLayerStack(s.layerStack, dirty); + } + + mVisibleRegionsDirty |= visibleRegions; + + // If we will need to wake up at some time in the future to deal with a + // queued frame that shouldn't be displayed during this vsync period, wake + // up during the next vsync period to check again. + if (frameQueued && layersWithQueuedFrames.empty()) { + signalLayerUpdate(); + } + + // Only continue with the refresh if there is actually new work to do + return !layersWithQueuedFrames.empty(); +} + +void SurfaceFlinger::invalidateHwcGeometry() +{ + mHwWorkListDirty = true; +} + + +void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw, + const Region& inDirtyRegion) +{ + // We only need to actually compose the display if: + // 1) It is being handled by hardware composer, which may need this to + // keep its virtual display state machine in sync, or + // 2) There is work to be done (the dirty region isn't empty) + bool isHwcDisplay = hw->getHwcDisplayId() >= 0; + if (!isHwcDisplay && inDirtyRegion.isEmpty()) { + return; + } + + Region dirtyRegion(inDirtyRegion); + + // compute the invalid region + hw->swapRegion.orSelf(dirtyRegion); + + uint32_t flags = hw->getFlags(); + if (flags & DisplayDevice::SWAP_RECTANGLE) { + // we can redraw only what's dirty, but since SWAP_RECTANGLE only + // takes a rectangle, we must make sure to update that whole + // rectangle in that case + dirtyRegion.set(hw->swapRegion.bounds()); + } else { + if (flags & DisplayDevice::PARTIAL_UPDATES) { + // We need to redraw the rectangle that will be updated + // (pushed to the framebuffer). + // This is needed because PARTIAL_UPDATES only takes one + // rectangle instead of a region (see DisplayDevice::flip()) + dirtyRegion.set(hw->swapRegion.bounds()); + } else { + // we need to redraw everything (the whole screen) + dirtyRegion.set(hw->bounds()); + hw->swapRegion = dirtyRegion; + } + } + + if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) { + if (!doComposeSurfaces(hw, dirtyRegion)) return; + } else { + RenderEngine& engine(getRenderEngine()); + mat4 colorMatrix = mColorMatrix; + if (mDaltonize) { + colorMatrix = colorMatrix * mDaltonizer(); + } + mat4 oldMatrix = engine.setupColorTransform(colorMatrix); + doComposeSurfaces(hw, dirtyRegion); + engine.setupColorTransform(oldMatrix); + } + + // update the swap region and clear the dirty region + hw->swapRegion.orSelf(dirtyRegion); + + // swap buffers (presentation) + hw->swapBuffers(getHwComposer()); +} + +bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty) +{ + RenderEngine& engine(getRenderEngine()); + const int32_t id = hw->getHwcDisplayId(); + HWComposer& hwc(getHwComposer()); + HWComposer::LayerListIterator cur = hwc.begin(id); + const HWComposer::LayerListIterator end = hwc.end(id); + + bool hasGlesComposition = hwc.hasGlesComposition(id); + if (hasGlesComposition) { + if (!hw->makeCurrent(mEGLDisplay, mEGLContext)) { + ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s", + hw->getDisplayName().string()); + eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) { + ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting."); + } + return false; + } + + // Never touch the framebuffer if we don't have any framebuffer layers + const bool hasHwcComposition = hwc.hasHwcComposition(id); + if (hasHwcComposition) { + // when using overlays, we assume a fully transparent framebuffer + // NOTE: we could reduce how much we need to clear, for instance + // remove where there are opaque FB layers. however, on some + // GPUs doing a "clean slate" clear might be more efficient. + // We'll revisit later if needed. + engine.clearWithColor(0, 0, 0, 0); + } else { + // we start with the whole screen area + const Region bounds(hw->getBounds()); + + // we remove the scissor part + // we're left with the letterbox region + // (common case is that letterbox ends-up being empty) + const Region letterbox(bounds.subtract(hw->getScissor())); + + // compute the area to clear + Region region(hw->undefinedRegion.merge(letterbox)); + + // but limit it to the dirty region + region.andSelf(dirty); + + // screen is already cleared here + if (!region.isEmpty()) { + // can happen with SurfaceView + drawWormhole(hw, region); + } + } + + if (hw->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) { + // just to be on the safe side, we don't set the + // scissor on the main display. It should never be needed + // anyways (though in theory it could since the API allows it). + const Rect& bounds(hw->getBounds()); + const Rect& scissor(hw->getScissor()); + if (scissor != bounds) { + // scissor doesn't match the screen's dimensions, so we + // need to clear everything outside of it and enable + // the GL scissor so we don't draw anything where we shouldn't + + // enable scissor for this frame + const uint32_t height = hw->getHeight(); + engine.setScissor(scissor.left, height - scissor.bottom, + scissor.getWidth(), scissor.getHeight()); + } + } + } + + /* + * and then, render the layers targeted at the framebuffer + */ + + const Vector< sp<Layer> >& layers(hw->getVisibleLayersSortedByZ()); + const size_t count = layers.size(); + const Transform& tr = hw->getTransform(); + if (cur != end) { + // we're using h/w composer + for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) { + const sp<Layer>& layer(layers[i]); + const Region clip(dirty.intersect(tr.transform(layer->visibleRegion))); + if (!clip.isEmpty()) { + switch (cur->getCompositionType()) { + case HWC_CURSOR_OVERLAY: + case HWC_OVERLAY: { + const Layer::State& state(layer->getDrawingState()); + if ((cur->getHints() & HWC_HINT_CLEAR_FB) + && i + && layer->isOpaque(state) && (state.alpha == 0xFF) + && hasGlesComposition) { + // never clear the very first layer since we're + // guaranteed the FB is already cleared + layer->clearWithOpenGL(hw, clip); + } + break; + } + case HWC_FRAMEBUFFER: { + layer->draw(hw, clip); + break; + } + case HWC_FRAMEBUFFER_TARGET: { + // this should not happen as the iterator shouldn't + // let us get there. + ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%zu)", i); + break; + } + } + } + layer->setAcquireFence(hw, *cur); + } + } else { + // we're not using h/w composer + for (size_t i=0 ; i<count ; ++i) { + const sp<Layer>& layer(layers[i]); + const Region clip(dirty.intersect( + tr.transform(layer->visibleRegion))); + if (!clip.isEmpty()) { + layer->draw(hw, clip); + } + } + } + + // disable scissor at the end of the frame + engine.disableScissor(); + return true; +} + +void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, const Region& region) const { + const int32_t height = hw->getHeight(); + RenderEngine& engine(getRenderEngine()); + engine.fillRegionWithColor(region, height, 0, 0, 0, 0); +} + +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); + + return NO_ERROR; +} + +status_t SurfaceFlinger::removeLayer(const wp<Layer>& weakLayer) { + Mutex::Autolock _l(mStateLock); + sp<Layer> layer = weakLayer.promote(); + if (layer == nullptr) { + // The layer has already been removed, carry on + return NO_ERROR; + } + + ssize_t index = mCurrentState.layersSortedByZ.remove(layer); + if (index >= 0) { + mLayersPendingRemoval.push(layer); + mLayersRemoved = true; + setTransactionFlags(eTransactionNeeded); + return NO_ERROR; + } + return status_t(index); +} + +uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t /* flags */) { + return android_atomic_release_load(&mTransactionFlags); +} + +uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) { + return android_atomic_and(~flags, &mTransactionFlags) & flags; +} + +uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) { + uint32_t old = android_atomic_or(flags, &mTransactionFlags); + if ((old & flags)==0) { // wake the server up + signalTransaction(); + } + return old; +} + +void SurfaceFlinger::setTransactionState( + const Vector<ComposerState>& state, + const Vector<DisplayState>& displays, + uint32_t flags) +{ + ATRACE_CALL(); + Mutex::Autolock _l(mStateLock); + uint32_t transactionFlags = 0; + + if (flags & eAnimation) { + // For window updates that are part of an animation we must wait for + // previous animation "frames" to be handled. + while (mAnimTransactionPending) { + status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); + if (CC_UNLIKELY(err != NO_ERROR)) { + // just in case something goes wrong in SF, return to the + // caller after a few seconds. + ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out " + "waiting for previous animation frame"); + mAnimTransactionPending = false; + break; + } + } + } + + size_t count = displays.size(); + for (size_t i=0 ; i<count ; i++) { + const DisplayState& s(displays[i]); + transactionFlags |= setDisplayStateLocked(s); + } + + count = state.size(); + for (size_t i=0 ; i<count ; i++) { + const ComposerState& s(state[i]); + // Here we need to check that the interface we're given is indeed + // one of our own. A malicious client could give us a NULL + // IInterface, or one of its own or even one of our own but a + // different type. All these situations would cause us to crash. + // + // NOTE: it would be better to use RTTI as we could directly check + // that we have a Client*. however, RTTI is disabled in Android. + if (s.client != NULL) { + sp<IBinder> binder = IInterface::asBinder(s.client); + if (binder != NULL) { + String16 desc(binder->getInterfaceDescriptor()); + if (desc == ISurfaceComposerClient::descriptor) { + sp<Client> client( static_cast<Client *>(s.client.get()) ); + transactionFlags |= setClientStateLocked(client, s.state); + } + } + } + } + + // If a synchronous transaction is explicitly requested without any changes, + // force a transaction anyway. This can be used as a flush mechanism for + // previous async transactions. + if (transactionFlags == 0 && (flags & eSynchronous)) { + transactionFlags = eTransactionNeeded; + } + + if (transactionFlags) { + if (mInterceptor.isEnabled()) { + mInterceptor.saveTransaction(state, mCurrentState.displays, displays, flags); + } + + // this triggers the transaction + setTransactionFlags(transactionFlags); + + // if this is a synchronous transaction, wait for it to take effect + // before returning. + if (flags & eSynchronous) { + mTransactionPending = true; + } + if (flags & eAnimation) { + mAnimTransactionPending = true; + } + while (mTransactionPending) { + status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5)); + if (CC_UNLIKELY(err != NO_ERROR)) { + // just in case something goes wrong in SF, return to the + // called after a few seconds. + ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!"); + mTransactionPending = false; + break; + } + } + } +} + +uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) +{ + ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token); + if (dpyIdx < 0) + return 0; + + uint32_t flags = 0; + DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx)); + if (disp.isValid()) { + const uint32_t what = s.what; + if (what & DisplayState::eSurfaceChanged) { + if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) { + disp.surface = s.surface; + flags |= eDisplayTransactionNeeded; + } + } + if (what & DisplayState::eLayerStackChanged) { + if (disp.layerStack != s.layerStack) { + disp.layerStack = s.layerStack; + flags |= eDisplayTransactionNeeded; + } + } + if (what & DisplayState::eDisplayProjectionChanged) { + if (disp.orientation != s.orientation) { + disp.orientation = s.orientation; + flags |= eDisplayTransactionNeeded; + } + if (disp.frame != s.frame) { + disp.frame = s.frame; + flags |= eDisplayTransactionNeeded; + } + if (disp.viewport != s.viewport) { + disp.viewport = s.viewport; + flags |= eDisplayTransactionNeeded; + } + } + if (what & DisplayState::eDisplaySizeChanged) { + if (disp.width != s.width) { + disp.width = s.width; + flags |= eDisplayTransactionNeeded; + } + if (disp.height != s.height) { + disp.height = s.height; + flags |= eDisplayTransactionNeeded; + } + } + } + return flags; +} + +uint32_t SurfaceFlinger::setClientStateLocked( + const sp<Client>& client, + const layer_state_t& s) +{ + uint32_t flags = 0; + sp<Layer> layer(client->getLayerUser(s.surface)); + if (layer != 0) { + const uint32_t what = s.what; + bool geometryAppliesWithResize = + what & layer_state_t::eGeometryAppliesWithResize; + if (what & layer_state_t::ePositionChanged) { + if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) { + flags |= eTraversalNeeded; + } + } + if (what & layer_state_t::eLayerChanged) { + // NOTE: index needs to be calculated before we update the state + ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); + if (layer->setLayer(s.z) && idx >= 0) { + mCurrentState.layersSortedByZ.removeAt(idx); + mCurrentState.layersSortedByZ.add(layer); + // we need traversal (state changed) + // AND transaction (list changed) + flags |= eTransactionNeeded|eTraversalNeeded; + } + } + if (what & layer_state_t::eSizeChanged) { + if (layer->setSize(s.w, s.h)) { + flags |= eTraversalNeeded; + } + } + if (what & layer_state_t::eAlphaChanged) { + if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f))) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eMatrixChanged) { + if (layer->setMatrix(s.matrix)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eTransparentRegionChanged) { + if (layer->setTransparentRegionHint(s.transparentRegion)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eFlagsChanged) { + if (layer->setFlags(s.flags, s.mask)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eCropChanged) { + if (layer->setCrop(s.crop, !geometryAppliesWithResize)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eFinalCropChanged) { + if (layer->setFinalCrop(s.finalCrop)) + flags |= eTraversalNeeded; + } + if (what & layer_state_t::eLayerStackChanged) { + // NOTE: index needs to be calculated before we update the state + ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); + if (layer->setLayerStack(s.layerStack) && idx >= 0) { + mCurrentState.layersSortedByZ.removeAt(idx); + mCurrentState.layersSortedByZ.add(layer); + // we need traversal (state changed) + // AND transaction (list changed) + flags |= eTransactionNeeded|eTraversalNeeded; + } + } + if (what & layer_state_t::eDeferTransaction) { + layer->deferTransactionUntil(s.handle, s.frameNumber); + // We don't trigger a traversal here because if no other state is + // changed, we don't want this to cause any more work + } + if (what & layer_state_t::eOverrideScalingModeChanged) { + layer->setOverrideScalingMode(s.overrideScalingMode); + // We don't trigger a traversal here because if no other state is + // changed, we don't want this to cause any more work + } + } + return flags; +} + +status_t SurfaceFlinger::createLayer( + const String8& name, + const sp<Client>& client, + uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, + sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) +{ + if (int32_t(w|h) < 0) { + ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)", + int(w), int(h)); + return BAD_VALUE; + } + + status_t result = NO_ERROR; + + sp<Layer> layer; + + switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { + case ISurfaceComposerClient::eFXSurfaceNormal: + result = createNormalLayer(client, + name, w, h, flags, format, + handle, gbp, &layer); + break; + case ISurfaceComposerClient::eFXSurfaceDim: + result = createDimLayer(client, + name, w, h, flags, + handle, gbp, &layer); + break; + default: + result = BAD_VALUE; + break; + } + + if (result != NO_ERROR) { + return result; + } + + result = addClientLayer(client, *handle, *gbp, layer); + if (result != NO_ERROR) { + return result; + } + mInterceptor.saveSurfaceCreation(layer); + + setTransactionFlags(eTransactionNeeded); + return result; +} + +status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client, + const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format, + sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) +{ + // initialize the surfaces + switch (format) { + case PIXEL_FORMAT_TRANSPARENT: + case PIXEL_FORMAT_TRANSLUCENT: + format = PIXEL_FORMAT_RGBA_8888; + break; + case PIXEL_FORMAT_OPAQUE: + format = PIXEL_FORMAT_RGBX_8888; + break; + } + + *outLayer = new Layer(this, client, name, w, h, flags); + status_t err = (*outLayer)->setBuffers(w, h, format, flags); + if (err == NO_ERROR) { + *handle = (*outLayer)->getHandle(); + *gbp = (*outLayer)->getProducer(); + } + + ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err)); + return err; +} + +status_t SurfaceFlinger::createDimLayer(const sp<Client>& client, + const String8& name, uint32_t w, uint32_t h, uint32_t flags, + sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) +{ + *outLayer = new LayerDim(this, client, name, w, h, flags); + *handle = (*outLayer)->getHandle(); + *gbp = (*outLayer)->getProducer(); + return NO_ERROR; +} + +status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle) +{ + // called by the window manager when it wants to remove a Layer + status_t err = NO_ERROR; + sp<Layer> l(client->getLayerUser(handle)); + if (l != NULL) { + mInterceptor.saveSurfaceDeletion(l); + err = removeLayer(l); + ALOGE_IF(err<0 && err != NAME_NOT_FOUND, + "error removing layer=%p (%s)", l.get(), strerror(-err)); + } + return err; +} + +status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer) +{ + // called by ~LayerCleaner() when all references to the IBinder (handle) + // are gone + return removeLayer(layer); +} + +// --------------------------------------------------------------------------- + +void SurfaceFlinger::onInitializeDisplays() { + // reset screen orientation and use primary layer stack + Vector<ComposerState> state; + Vector<DisplayState> displays; + DisplayState d; + d.what = DisplayState::eDisplayProjectionChanged | + DisplayState::eLayerStackChanged; + d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]; + d.layerStack = 0; + d.orientation = DisplayState::eOrientationDefault; + d.frame.makeInvalid(); + d.viewport.makeInvalid(); + d.width = 0; + d.height = 0; + displays.add(d); + setTransactionState(state, displays, 0); + setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL); + + const nsecs_t period = + getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); + mAnimFrameTracker.setDisplayRefreshPeriod(period); +} + +void SurfaceFlinger::initializeDisplays() { + class MessageScreenInitialized : public MessageBase { + SurfaceFlinger* flinger; + public: + explicit MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { } + virtual bool handler() { + flinger->onInitializeDisplays(); + return true; + } + }; + sp<MessageBase> msg = new MessageScreenInitialized(this); + postMessageAsync(msg); // we may be called from main thread, use async message +} + +void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, + int mode) { + ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(), + this); + int32_t type = hw->getDisplayType(); + int currentMode = hw->getPowerMode(); + + if (mode == currentMode) { + ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode); + return; + } + + hw->setPowerMode(mode); + if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { + ALOGW("Trying to set power mode for virtual display"); + return; + } + + if (mInterceptor.isEnabled()) { + Mutex::Autolock _l(mStateLock); + ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken()); + if (idx < 0) { + ALOGW("Surface Interceptor SavePowerMode: invalid display token"); + return; + } + mInterceptor.savePowerModeUpdate(mCurrentState.displays.valueAt(idx).displayId, mode); + } + + if (currentMode == HWC_POWER_MODE_OFF) { + // Turn on the display + getHwComposer().setPowerMode(type, mode); + if (type == DisplayDevice::DISPLAY_PRIMARY) { + // FIXME: eventthread only knows about the main display right now + mEventThread->onScreenAcquired(); + resyncToHardwareVsync(true); + } + + mVisibleRegionsDirty = true; + mHasPoweredOff = true; + repaintEverything(); + + struct sched_param param = {0}; + param.sched_priority = 1; + if (sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) { + ALOGW("Couldn't set SCHED_FIFO on display on"); + } + } else if (mode == HWC_POWER_MODE_OFF) { + // Turn off the display + struct sched_param param = {0}; + if (sched_setscheduler(0, SCHED_OTHER, ¶m) != 0) { + ALOGW("Couldn't set SCHED_OTHER on display off"); + } + + if (type == DisplayDevice::DISPLAY_PRIMARY) { + disableHardwareVsync(true); // also cancels any in-progress resync + + // FIXME: eventthread only knows about the main display right now + mEventThread->onScreenReleased(); + } + + getHwComposer().setPowerMode(type, mode); + mVisibleRegionsDirty = true; + // from this point on, SF will stop drawing on this display + } else { + getHwComposer().setPowerMode(type, mode); + } +} + +void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) { + class MessageSetPowerMode: public MessageBase { + SurfaceFlinger& mFlinger; + sp<IBinder> mDisplay; + int mMode; + public: + MessageSetPowerMode(SurfaceFlinger& flinger, + const sp<IBinder>& disp, int mode) : mFlinger(flinger), + mDisplay(disp) { mMode = mode; } + virtual bool handler() { + sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay)); + if (hw == NULL) { + ALOGE("Attempt to set power mode = %d for null display %p", + mMode, mDisplay.get()); + } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) { + ALOGW("Attempt to set power mode = %d for virtual display", + mMode); + } else { + mFlinger.setPowerModeInternal(hw, mMode); + } + return true; + } + }; + sp<MessageBase> msg = new MessageSetPowerMode(*this, display, mode); + postMessageSync(msg); +} + +// --------------------------------------------------------------------------- + +status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) +{ + String8 result; + + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) && + !PermissionCache::checkPermission(sDump, pid, uid)) { + result.appendFormat("Permission Denial: " + "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); + } else { + // Try to get the main lock, but give up after one second + // (this would indicate SF is stuck, but we want to be able to + // print something in dumpsys). + status_t err = mStateLock.timedLock(s2ns(1)); + bool locked = (err == NO_ERROR); + if (!locked) { + result.appendFormat( + "SurfaceFlinger appears to be unresponsive (%s [%d]), " + "dumping anyways (no locks held)\n", strerror(-err), err); + } + + bool dumpAll = true; + size_t index = 0; + size_t numArgs = args.size(); + if (numArgs) { + if ((index < numArgs) && + (args[index] == String16("--list"))) { + index++; + listLayersLocked(args, index, result); + dumpAll = false; + } + + if ((index < numArgs) && + (args[index] == String16("--latency"))) { + index++; + dumpStatsLocked(args, index, result); + dumpAll = false; + } + + if ((index < numArgs) && + (args[index] == String16("--latency-clear"))) { + index++; + clearStatsLocked(args, index, result); + dumpAll = false; + } + + if ((index < numArgs) && + (args[index] == String16("--dispsync"))) { + index++; + mPrimaryDispSync.dump(result); + dumpAll = false; + } + + if ((index < numArgs) && + (args[index] == String16("--static-screen"))) { + index++; + dumpStaticScreenStats(result); + dumpAll = false; + } + + if ((index < numArgs) && + (args[index] == String16("--fences"))) { + index++; + mFenceTracker.dump(&result); + dumpAll = false; + } + } + + if (dumpAll) { + dumpAllLocked(args, index, result); + } + + if (locked) { + mStateLock.unlock(); + } + } + write(fd, result.string(), result.size()); + return NO_ERROR; +} + +void SurfaceFlinger::listLayersLocked(const Vector<String16>& /* args */, + size_t& /* index */, String8& result) const +{ + const LayerVector& currentLayers = mCurrentState.layersSortedByZ; + const size_t count = currentLayers.size(); + for (size_t i=0 ; i<count ; i++) { + const sp<Layer>& layer(currentLayers[i]); + result.appendFormat("%s\n", layer->getName().string()); + } +} + +void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index, + String8& result) const +{ + String8 name; + if (index < args.size()) { + name = String8(args[index]); + index++; + } + + const nsecs_t period = + getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); + result.appendFormat("%" PRId64 "\n", period); + + if (name.isEmpty()) { + mAnimFrameTracker.dumpStats(result); + } else { + const LayerVector& currentLayers = mCurrentState.layersSortedByZ; + const size_t count = currentLayers.size(); + for (size_t i=0 ; i<count ; i++) { + const sp<Layer>& layer(currentLayers[i]); + if (name == layer->getName()) { + layer->dumpFrameStats(result); + } + } + } +} + +void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index, + String8& /* result */) +{ + String8 name; + if (index < args.size()) { + name = String8(args[index]); + index++; + } + + const LayerVector& currentLayers = mCurrentState.layersSortedByZ; + const size_t count = currentLayers.size(); + for (size_t i=0 ; i<count ; i++) { + const sp<Layer>& layer(currentLayers[i]); + if (name.isEmpty() || (name == layer->getName())) { + layer->clearFrameStats(); + } + } + + mAnimFrameTracker.clearStats(); +} + +// This should only be called from the main thread. Otherwise it would need +// the lock and should use mCurrentState rather than mDrawingState. +void SurfaceFlinger::logFrameStats() { + const LayerVector& drawingLayers = mDrawingState.layersSortedByZ; + const size_t count = drawingLayers.size(); + for (size_t i=0 ; i<count ; i++) { + const sp<Layer>& layer(drawingLayers[i]); + layer->logFrameStats(); + } + + mAnimFrameTracker.logAndResetStats(String8("<win-anim>")); +} + +/*static*/ void SurfaceFlinger::appendSfConfigString(String8& result) +{ + static const char* config = + " [sf" +#ifdef HAS_CONTEXT_PRIORITY + " HAS_CONTEXT_PRIORITY" +#endif +#ifdef NEVER_DEFAULT_TO_ASYNC_MODE + " NEVER_DEFAULT_TO_ASYNC_MODE" +#endif +#ifdef TARGET_DISABLE_TRIPLE_BUFFERING + " TARGET_DISABLE_TRIPLE_BUFFERING" +#endif + "]"; + 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::recordBufferingStats(const char* layerName, + std::vector<OccupancyTracker::Segment>&& history) { + Mutex::Autolock lock(mBufferingStatsMutex); + auto& stats = mBufferingStats[layerName]; + for (const auto& segment : history) { + if (!segment.usedThirdBuffer) { + stats.twoBufferTime += segment.totalTime; + } + if (segment.occupancyAverage < 1.0f) { + stats.doubleBufferedTime += segment.totalTime; + } else if (segment.occupancyAverage < 2.0f) { + stats.tripleBufferedTime += segment.totalTime; + } + ++stats.numSegments; + stats.totalTime += segment.totalTime; + } +} + +void SurfaceFlinger::dumpBufferingStats(String8& result) const { + result.append("Buffering stats:\n"); + result.append(" [Layer name] <Active time> <Two buffer> " + "<Double buffered> <Triple buffered>\n"); + Mutex::Autolock lock(mBufferingStatsMutex); + typedef std::tuple<std::string, float, float, float> BufferTuple; + std::map<float, BufferTuple, std::greater<float>> sorted; + for (const auto& statsPair : mBufferingStats) { + const char* name = statsPair.first.c_str(); + const BufferingStats& stats = statsPair.second; + if (stats.numSegments == 0) { + continue; + } + float activeTime = ns2ms(stats.totalTime) / 1000.0f; + float twoBufferRatio = static_cast<float>(stats.twoBufferTime) / + stats.totalTime; + float doubleBufferRatio = static_cast<float>( + stats.doubleBufferedTime) / stats.totalTime; + float tripleBufferRatio = static_cast<float>( + stats.tripleBufferedTime) / stats.totalTime; + sorted.insert({activeTime, {name, twoBufferRatio, + doubleBufferRatio, tripleBufferRatio}}); + } + for (const auto& sortedPair : sorted) { + float activeTime = sortedPair.first; + const BufferTuple& values = sortedPair.second; + result.appendFormat(" [%s] %.2f %.3f %.3f %.3f\n", + std::get<0>(values).c_str(), activeTime, + std::get<1>(values), std::get<2>(values), + std::get<3>(values)); + } + result.append("\n"); +} + +void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, + String8& result) const +{ + bool colorize = false; + if (index < args.size() + && (args[index] == String16("--color"))) { + colorize = true; + index++; + } + + Colorizer colorizer(colorize); + + // figure out if we're stuck somewhere + const nsecs_t now = systemTime(); + const nsecs_t inSwapBuffers(mDebugInSwapBuffers); + const nsecs_t inTransaction(mDebugInTransaction); + nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0; + nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0; + + /* + * Dump library configuration. + */ + + colorizer.bold(result); + result.append("Build configuration:"); + colorizer.reset(result); + appendSfConfigString(result); + appendUiConfigString(result); + appendGuiConfigString(result); + result.append("\n"); + + colorizer.bold(result); + result.append("Sync configuration: "); + colorizer.reset(result); + result.append(SyncFeatures::getInstance().toString()); + result.append("\n"); + + colorizer.bold(result); + result.append("DispSync configuration: "); + colorizer.reset(result); + result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, " + "present offset %d ns (refresh %" PRId64 " ns)", + vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS, + mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY)); + result.append("\n"); + + // Dump static screen stats + result.append("\n"); + dumpStaticScreenStats(result); + result.append("\n"); + + dumpBufferingStats(result); + + /* + * Dump the visible layer list + */ + const LayerVector& currentLayers = mCurrentState.layersSortedByZ; + const size_t count = currentLayers.size(); + colorizer.bold(result); + result.appendFormat("Visible layers (count = %zu)\n", count); + colorizer.reset(result); + for (size_t i=0 ; i<count ; i++) { + const sp<Layer>& layer(currentLayers[i]); + layer->dump(result, colorizer); + } + + /* + * Dump Display state + */ + + colorizer.bold(result); + result.appendFormat("Displays (%zu entries)\n", mDisplays.size()); + colorizer.reset(result); + for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { + const sp<const DisplayDevice>& hw(mDisplays[dpy]); + hw->dump(result); + } + + /* + * Dump SurfaceFlinger global state + */ + + colorizer.bold(result); + result.append("SurfaceFlinger global state:\n"); + colorizer.reset(result); + + HWComposer& hwc(getHwComposer()); + sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + + colorizer.bold(result); + result.appendFormat("EGL implementation : %s\n", + eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION)); + colorizer.reset(result); + result.appendFormat("%s\n", + eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS)); + + mRenderEngine->dump(result); + + hw->undefinedRegion.dump(result, "undefinedRegion"); + result.appendFormat(" orientation=%d, isDisplayOn=%d\n", + hw->getOrientation(), hw->isDisplayOn()); + result.appendFormat( + " last eglSwapBuffers() time: %f us\n" + " last transaction time : %f us\n" + " transaction-flags : %08x\n" + " refresh-rate : %f fps\n" + " x-dpi : %f\n" + " y-dpi : %f\n" + " gpu_to_cpu_unsupported : %d\n" + , + mLastSwapBufferTime/1000.0, + mLastTransactionTime/1000.0, + mTransactionFlags, + 1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY), + hwc.getDpiX(HWC_DISPLAY_PRIMARY), + hwc.getDpiY(HWC_DISPLAY_PRIMARY), + !mGpuToCpuSupported); + + result.appendFormat(" eglSwapBuffers time: %f us\n", + inSwapBuffersDuration/1000.0); + + result.appendFormat(" transaction time: %f us\n", + inTransactionDuration/1000.0); + + /* + * VSYNC state + */ + mEventThread->dump(result); + + /* + * Dump HWComposer state + */ + colorizer.bold(result); + result.append("h/w composer state:\n"); + colorizer.reset(result); + result.appendFormat(" h/w composer %s and %s\n", + hwc.initCheck()==NO_ERROR ? "present" : "not present", + (mDebugDisableHWC || mDebugRegion || mDaltonize + || mHasColorMatrix) ? "disabled" : "enabled"); + hwc.dump(result); + + /* + * Dump gralloc state + */ + const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); + alloc.dump(result); +} + +const Vector< sp<Layer> >& +SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) { + // Note: mStateLock is held here + wp<IBinder> dpy; + for (size_t i=0 ; i<mDisplays.size() ; i++) { + if (mDisplays.valueAt(i)->getHwcDisplayId() == id) { + dpy = mDisplays.keyAt(i); + break; + } + } + if (dpy == NULL) { + ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id); + // Just use the primary display so we have something to return + dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY); + } + return getDisplayDevice(dpy)->getVisibleLayersSortedByZ(); +} + +bool SurfaceFlinger::startDdmConnection() +{ + void* libddmconnection_dso = + dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW); + if (!libddmconnection_dso) { + return false; + } + void (*DdmConnection_start)(const char* name); + DdmConnection_start = + (decltype(DdmConnection_start))dlsym(libddmconnection_dso, "DdmConnection_start"); + if (!DdmConnection_start) { + dlclose(libddmconnection_dso); + return false; + } + (*DdmConnection_start)(getServiceName()); + return true; +} + +status_t SurfaceFlinger::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch (code) { + case CREATE_CONNECTION: + case CREATE_DISPLAY: + case SET_TRANSACTION_STATE: + case BOOT_FINISHED: + case CLEAR_ANIMATION_FRAME_STATS: + case GET_ANIMATION_FRAME_STATS: + case SET_POWER_MODE: + case GET_HDR_CAPABILITIES: + { + // codes that require permission check + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + 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); + return PERMISSION_DENIED; + } + break; + } + case CAPTURE_SCREEN: + { + // codes that require permission check + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_GRAPHICS) && + !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { + ALOGE("Permission Denial: " + "can't read framebuffer pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + break; + } + } + + status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags); + if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + if (CC_UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + ALOGE("Permission Denial: " + "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + int n; + switch (code) { + case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE + case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE + return NO_ERROR; + case 1002: // SHOW_UPDATES + n = data.readInt32(); + mDebugRegion = n ? n : (mDebugRegion ? 0 : 1); + invalidateHwcGeometry(); + repaintEverything(); + return NO_ERROR; + case 1004:{ // repaint everything + repaintEverything(); + return NO_ERROR; + } + case 1005:{ // force transaction + setTransactionFlags( + eTransactionNeeded| + eDisplayTransactionNeeded| + eTraversalNeeded); + return NO_ERROR; + } + case 1006:{ // send empty update + signalRefresh(); + return NO_ERROR; + } + case 1008: // toggle use of hw composer + n = data.readInt32(); + mDebugDisableHWC = n ? 1 : 0; + invalidateHwcGeometry(); + repaintEverything(); + return NO_ERROR; + case 1009: // toggle use of transform hint + n = data.readInt32(); + mDebugDisableTransformHint = n ? 1 : 0; + invalidateHwcGeometry(); + repaintEverything(); + return NO_ERROR; + case 1010: // interrogate. + reply->writeInt32(0); + reply->writeInt32(0); + reply->writeInt32(mDebugRegion); + reply->writeInt32(0); + reply->writeInt32(mDebugDisableHWC); + return NO_ERROR; + case 1013: { + Mutex::Autolock _l(mStateLock); + sp<const DisplayDevice> hw(getDefaultDisplayDevice()); + reply->writeInt32(hw->getPageFlipCount()); + return NO_ERROR; + } + case 1014: { + // daltonize + n = data.readInt32(); + switch (n % 10) { + case 1: + mDaltonizer.setType(ColorBlindnessType::Protanomaly); + break; + case 2: + mDaltonizer.setType(ColorBlindnessType::Deuteranomaly); + break; + case 3: + mDaltonizer.setType(ColorBlindnessType::Tritanomaly); + break; + } + if (n >= 10) { + mDaltonizer.setMode(ColorBlindnessMode::Correction); + } else { + mDaltonizer.setMode(ColorBlindnessMode::Simulation); + } + mDaltonize = n > 0; + invalidateHwcGeometry(); + repaintEverything(); + return NO_ERROR; + } + case 1015: { + // apply a color matrix + n = data.readInt32(); + mHasColorMatrix = n ? 1 : 0; + if (n) { + // color matrix is sent as mat3 matrix followed by vec3 + // offset, then packed into a mat4 where the last row is + // the offset and extra values are 0 + for (size_t i = 0 ; i < 4; i++) { + for (size_t j = 0; j < 4; j++) { + mColorMatrix[i][j] = data.readFloat(); + } + } + } else { + mColorMatrix = mat4(); + } + invalidateHwcGeometry(); + repaintEverything(); + return NO_ERROR; + } + // This is an experimental interface + // Needs to be shifted to proper binder interface when we productize + case 1016: { + n = data.readInt32(); + mPrimaryDispSync.setRefreshSkipCount(n); + return NO_ERROR; + } + case 1017: { + n = data.readInt32(); + mForceFullDamage = static_cast<bool>(n); + return NO_ERROR; + } + case 1018: { // Modify Choreographer's phase offset + n = data.readInt32(); + mEventThread->setPhaseOffset(static_cast<nsecs_t>(n)); + return NO_ERROR; + } + case 1019: { // Modify SurfaceFlinger's phase offset + n = data.readInt32(); + mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n)); + return NO_ERROR; + } + case 1020: { // Layer updates interceptor + n = data.readInt32(); + if (n) { + ALOGV("Interceptor enabled"); + mInterceptor.enable(mDrawingState.layersSortedByZ, mDrawingState.displays); + } + else{ + ALOGV("Interceptor disabled"); + mInterceptor.disable(); + } + return NO_ERROR; + } + case 1021: { // Disable HWC virtual displays + n = data.readInt32(); + mUseHwcVirtualDisplays = !n; + return NO_ERROR; + } + } + } + return err; +} + +void SurfaceFlinger::repaintEverything() { + android_atomic_or(1, &mRepaintEverything); + signalTransaction(); +} + +// --------------------------------------------------------------------------- +// Capture screen into an IGraphiBufferProducer +// --------------------------------------------------------------------------- + +/* The code below is here to handle b/8734824 + * + * We create a IGraphicBufferProducer wrapper that forwards all calls + * from the surfaceflinger thread to the calling binder thread, where they + * are executed. This allows the calling thread in the calling process to be + * reused and not depend on having "enough" binder threads to handle the + * requests. + */ +class GraphicProducerWrapper : public BBinder, public MessageHandler { + /* Parts of GraphicProducerWrapper are run on two different threads, + * communicating by sending messages via Looper but also by shared member + * data. Coherence maintenance is subtle and in places implicit (ugh). + * + * Don't rely on Looper's sendMessage/handleMessage providing + * release/acquire semantics for any data not actually in the Message. + * Data going from surfaceflinger to binder threads needs to be + * synchronized explicitly. + * + * Barrier open/wait do provide release/acquire semantics. This provides + * implicit synchronization for data coming back from binder to + * surfaceflinger threads. + */ + + sp<IGraphicBufferProducer> impl; + sp<Looper> looper; + status_t result; + bool exitPending; + bool exitRequested; + Barrier barrier; + uint32_t code; + Parcel const* data; + Parcel* reply; + + enum { + MSG_API_CALL, + MSG_EXIT + }; + + /* + * Called on surfaceflinger thread. This is called by our "fake" + * BpGraphicBufferProducer. We package the data and reply Parcel and + * forward them to the binder thread. + */ + virtual status_t transact(uint32_t code, + const Parcel& data, Parcel* reply, uint32_t /* flags */) { + this->code = code; + this->data = &data; + this->reply = reply; + if (exitPending) { + // if we've exited, we run the message synchronously right here. + // note (JH): as far as I can tell from looking at the code, this + // never actually happens. if it does, i'm not sure if it happens + // on the surfaceflinger or binder thread. + handleMessage(Message(MSG_API_CALL)); + } else { + barrier.close(); + // Prevent stores to this->{code, data, reply} from being + // reordered later than the construction of Message. + atomic_thread_fence(memory_order_release); + looper->sendMessage(this, Message(MSG_API_CALL)); + barrier.wait(); + } + return result; + } + + /* + * here we run on the binder thread. All we've got to do is + * call the real BpGraphicBufferProducer. + */ + virtual void handleMessage(const Message& message) { + int what = message.what; + // Prevent reads below from happening before the read from Message + atomic_thread_fence(memory_order_acquire); + if (what == MSG_API_CALL) { + result = IInterface::asBinder(impl)->transact(code, data[0], reply); + barrier.open(); + } else if (what == MSG_EXIT) { + exitRequested = true; + } + } + +public: + explicit GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl) + : impl(impl), + looper(new Looper(true)), + result(NO_ERROR), + exitPending(false), + exitRequested(false), + code(0), + data(NULL), + reply(NULL) + {} + + // Binder thread + status_t waitForResponse() { + do { + looper->pollOnce(-1); + } while (!exitRequested); + return result; + } + + // Client thread + void exit(status_t result) { + this->result = result; + exitPending = true; + // Ensure this->result is visible to the binder thread before it + // handles the message. + atomic_thread_fence(memory_order_release); + looper->sendMessage(this, Message(MSG_EXIT)); + } +}; + + +status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, + const sp<IGraphicBufferProducer>& producer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { + + if (CC_UNLIKELY(display == 0)) + return BAD_VALUE; + + if (CC_UNLIKELY(producer == 0)) + return BAD_VALUE; + + // if we have secure windows on this display, never allow the screen capture + // unless the producer interface is local (i.e.: we can take a screenshot for + // ourselves). + bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder(); + + // Convert to surfaceflinger's internal rotation type. + Transform::orientation_flags rotationFlags; + switch (rotation) { + case ISurfaceComposer::eRotateNone: + rotationFlags = Transform::ROT_0; + break; + case ISurfaceComposer::eRotate90: + rotationFlags = Transform::ROT_90; + break; + case ISurfaceComposer::eRotate180: + rotationFlags = Transform::ROT_180; + break; + case ISurfaceComposer::eRotate270: + rotationFlags = Transform::ROT_270; + break; + default: + rotationFlags = Transform::ROT_0; + ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation); + break; + } + + class MessageCaptureScreen : public MessageBase { + SurfaceFlinger* flinger; + sp<IBinder> display; + sp<IGraphicBufferProducer> producer; + Rect sourceCrop; + uint32_t reqWidth, reqHeight; + uint32_t minLayerZ,maxLayerZ; + bool useIdentityTransform; + Transform::orientation_flags rotation; + status_t result; + bool isLocalScreenshot; + public: + MessageCaptureScreen(SurfaceFlinger* flinger, + const sp<IBinder>& display, + const sp<IGraphicBufferProducer>& producer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useIdentityTransform, + Transform::orientation_flags rotation, + bool isLocalScreenshot) + : flinger(flinger), display(display), producer(producer), + sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight), + minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), + useIdentityTransform(useIdentityTransform), + rotation(rotation), result(PERMISSION_DENIED), + isLocalScreenshot(isLocalScreenshot) + { + } + status_t getResult() const { + return result; + } + virtual bool handler() { + Mutex::Autolock _l(flinger->mStateLock); + sp<const DisplayDevice> hw(flinger->getDisplayDevice(display)); + result = flinger->captureScreenImplLocked(hw, producer, + sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, + useIdentityTransform, rotation, isLocalScreenshot); + static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result); + return true; + } + }; + + // this creates a "fake" BBinder which will serve as a "fake" remote + // binder to receive the marshaled calls and forward them to the + // real remote (a BpGraphicBufferProducer) + sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer); + + // the asInterface() call below creates our "fake" BpGraphicBufferProducer + // which does the marshaling work forwards to our "fake remote" above. + sp<MessageBase> msg = new MessageCaptureScreen(this, + display, IGraphicBufferProducer::asInterface( wrapper ), + sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, + useIdentityTransform, rotationFlags, isLocalScreenshot); + + status_t res = postMessageAsync(msg); + if (res == NO_ERROR) { + res = wrapper->waitForResponse(); + } + return res; +} + + +void SurfaceFlinger::renderScreenImplLocked( + const sp<const DisplayDevice>& hw, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation) +{ + ATRACE_CALL(); + RenderEngine& engine(getRenderEngine()); + + // get screen geometry + const int32_t hw_w = hw->getWidth(); + const int32_t hw_h = hw->getHeight(); + const bool filtering = static_cast<int32_t>(reqWidth) != hw_w || + static_cast<int32_t>(reqHeight) != hw_h; + + // if a default or invalid sourceCrop is passed in, set reasonable values + if (sourceCrop.width() == 0 || sourceCrop.height() == 0 || + !sourceCrop.isValid()) { + sourceCrop.setLeftTop(Point(0, 0)); + sourceCrop.setRightBottom(Point(hw_w, hw_h)); + } + + // ensure that sourceCrop is inside screen + if (sourceCrop.left < 0) { + ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left); + } + if (sourceCrop.right > hw_w) { + ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w); + } + if (sourceCrop.top < 0) { + ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top); + } + if (sourceCrop.bottom > hw_h) { + ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h); + } + + // make sure to clear all GL error flags + engine.checkErrors(); + + // set-up our viewport + engine.setViewportAndProjection( + reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation); + engine.disableTexturing(); + + // redraw the screen entirely... + engine.clearWithColor(0, 0, 0, 1); + + const LayerVector& layers( mDrawingState.layersSortedByZ ); + const size_t count = layers.size(); + for (size_t i=0 ; i<count ; ++i) { + const sp<Layer>& layer(layers[i]); + const Layer::State& state(layer->getDrawingState()); + if (state.layerStack == hw->getLayerStack()) { + if (state.z >= minLayerZ && state.z <= maxLayerZ) { + if (layer->isVisible()) { + if (filtering) layer->setFiltering(true); + layer->draw(hw, useIdentityTransform); + if (filtering) layer->setFiltering(false); + } + } + } + } + + // compositionComplete is needed for older driver + hw->compositionComplete(); + hw->setViewportAndProjection(); +} + + +status_t SurfaceFlinger::captureScreenImplLocked( + const sp<const DisplayDevice>& hw, + const sp<IGraphicBufferProducer>& producer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useIdentityTransform, Transform::orientation_flags rotation, + bool isLocalScreenshot) +{ + ATRACE_CALL(); + + // get screen geometry + 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)", + reqWidth, reqHeight, hw_w, hw_h); + return BAD_VALUE; + } + + reqWidth = (!reqWidth) ? hw_w : reqWidth; + reqHeight = (!reqHeight) ? hw_h : reqHeight; + + bool secureLayerIsVisible = false; + const LayerVector& layers(mDrawingState.layersSortedByZ); + const size_t count = layers.size(); + for (size_t i = 0 ; i < count ; ++i) { + const sp<Layer>& layer(layers[i]); + const Layer::State& state(layer->getDrawingState()); + if (state.layerStack == hw->getLayerStack() && state.z >= minLayerZ && + state.z <= maxLayerZ && layer->isVisible() && + layer->isSecure()) { + secureLayerIsVisible = true; + } + } + + if (!isLocalScreenshot && secureLayerIsVisible) { + ALOGW("FB is protected: PERMISSION_DENIED"); + return PERMISSION_DENIED; + } + + // create a surface (because we're a producer, and we need to + // dequeue/queue a buffer) + sp<Surface> sur = new Surface(producer, false); + ANativeWindow* window = sur.get(); + + 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; + + int err = 0; + err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight); + err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); + err |= native_window_set_usage(window, usage); + + if (err == NO_ERROR) { + ANativeWindowBuffer* buffer; + /* TODO: Once we have the sync framework everywhere this can use + * server-side waits on the fence that dequeueBuffer returns. + */ + result = native_window_dequeue_buffer_and_wait(window, &buffer); + if (result == NO_ERROR) { + int syncFd = -1; + // create an EGLImage from the buffer so we can later + // turn it into a texture + EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, + EGL_NATIVE_BUFFER_ANDROID, buffer, NULL); + if (image != EGL_NO_IMAGE_KHR) { + // this binds the given EGLImage as a framebuffer for the + // duration of this scope. + RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image); + if (imageBond.getStatus() == NO_ERROR) { + // this will in fact render into our dequeued buffer + // via an FBO, which means we didn't have to create + // an EGLSurface and therefore we're not + // dependent on the context's EGLConfig. + renderScreenImplLocked( + hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true, + useIdentityTransform, rotation); + + // Attempt to create a sync khr object that can produce a sync point. If that + // isn't available, create a non-dupable sync object in the fallback path and + // wait on it directly. + EGLSyncKHR sync; + if (!DEBUG_SCREENSHOTS) { + sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); + // native fence fd will not be populated until flush() is done. + getRenderEngine().flush(); + } else { + sync = EGL_NO_SYNC_KHR; + } + if (sync != EGL_NO_SYNC_KHR) { + // get the sync fd + syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync); + if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { + ALOGW("captureScreen: failed to dup sync khr object"); + syncFd = -1; + } + eglDestroySyncKHR(mEGLDisplay, sync); + } else { + // fallback path + sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL); + if (sync != EGL_NO_SYNC_KHR) { + EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, + EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/); + EGLint eglErr = eglGetError(); + if (result == EGL_TIMEOUT_EXPIRED_KHR) { + ALOGW("captureScreen: fence wait timed out"); + } else { + ALOGW_IF(eglErr != EGL_SUCCESS, + "captureScreen: error waiting on EGL fence: %#x", eglErr); + } + eglDestroySyncKHR(mEGLDisplay, sync); + } else { + ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError()); + } + } + if (DEBUG_SCREENSHOTS) { + uint32_t* pixels = new uint32_t[reqWidth*reqHeight]; + getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels); + checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, + hw, minLayerZ, maxLayerZ); + delete [] pixels; + } + + } else { + ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot"); + result = INVALID_OPERATION; + window->cancelBuffer(window, buffer, syncFd); + buffer = NULL; + } + // destroy our image + eglDestroyImageKHR(mEGLDisplay, image); + } else { + result = BAD_VALUE; + } + if (buffer) { + // queueBuffer takes ownership of syncFd + result = window->queueBuffer(window, buffer, syncFd); + } + } + } else { + result = BAD_VALUE; + } + native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); + } + + return result; +} + +bool SurfaceFlinger::getFrameTimestamps(const Layer& layer, + uint64_t frameNumber, FrameTimestamps* outTimestamps) { + return mFenceTracker.getFrameTimestamps(layer, frameNumber, outTimestamps); +} + +void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr, + const sp<const DisplayDevice>& hw, uint32_t minLayerZ, uint32_t maxLayerZ) { + if (DEBUG_SCREENSHOTS) { + for (size_t y=0 ; y<h ; y++) { + uint32_t const * p = (uint32_t const *)vaddr + y*s; + for (size_t x=0 ; x<w ; x++) { + if (p[x] != 0xFF000000) return; + } + } + ALOGE("*** we just took a black screenshot ***\n" + "requested minz=%d, maxz=%d, layerStack=%d", + minLayerZ, maxLayerZ, hw->getLayerStack()); + const LayerVector& layers( mDrawingState.layersSortedByZ ); + const size_t count = layers.size(); + for (size_t i=0 ; i<count ; ++i) { + const sp<Layer>& layer(layers[i]); + const Layer::State& state(layer->getDrawingState()); + const bool visible = (state.layerStack == hw->getLayerStack()) + && (state.z >= minLayerZ && state.z <= maxLayerZ) + && (layer->isVisible()); + ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%x", + visible ? '+' : '-', + i, layer->getName().string(), state.layerStack, state.z, + layer->isVisible(), state.flags, state.alpha); + } + } +} + +// --------------------------------------------------------------------------- + +SurfaceFlinger::LayerVector::LayerVector() { +} + +SurfaceFlinger::LayerVector::LayerVector(const LayerVector& rhs) + : SortedVector<sp<Layer> >(rhs) { +} + +int SurfaceFlinger::LayerVector::do_compare(const void* lhs, + const void* rhs) const +{ + // sort layers per layer-stack, then by z-order and finally by sequence + const sp<Layer>& l(*reinterpret_cast<const sp<Layer>*>(lhs)); + const sp<Layer>& r(*reinterpret_cast<const sp<Layer>*>(rhs)); + + uint32_t ls = l->getCurrentState().layerStack; + uint32_t rs = r->getCurrentState().layerStack; + if (ls != rs) + return ls - rs; + + uint32_t lz = l->getCurrentState().z; + uint32_t rz = r->getCurrentState().z; + if (lz != rz) + return lz - rz; + + return l->sequence - r->sequence; +} + +}; // namespace android + + +#if defined(__gl_h_) +#error "don't include gl/gl.h in this file" +#endif + +#if defined(__gl2_h_) +#error "don't include gl2/gl2.h in this file" +#endif |