diff options
Diffstat (limited to 'services/surfaceflinger')
43 files changed, 2775 insertions, 147 deletions
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 1eb2361..c1ddba1 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -13,6 +13,7 @@ LOCAL_SRC_FILES := \ FrameTracker.cpp \ Layer.cpp \ LayerDim.cpp \ + LayerBlur.cpp \ MessageQueue.cpp \ MonitoredProducer.cpp \ SurfaceFlinger.cpp \ @@ -34,10 +35,15 @@ LOCAL_SRC_FILES := \ RenderEngine/Texture.cpp \ RenderEngine/GLES10RenderEngine.cpp \ RenderEngine/GLES11RenderEngine.cpp \ - RenderEngine/GLES20RenderEngine.cpp - + RenderEngine/GLES20RenderEngine.cpp \ + DisplayUtils.cpp LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\" + +ifeq ($(TARGET_BUILD_VARIANT),userdebug) +LOCAL_CFLAGS += -DDEBUG_CONT_DUMPSYS +endif + LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES ifeq ($(TARGET_BOARD_PLATFORM),omap4) @@ -106,6 +112,24 @@ LOCAL_SHARED_LIBRARIES := \ libgui \ libpowermanager +ifeq ($(TARGET_USES_QCOM_BSP), true) + LOCAL_C_INCLUDES += $(call project-path-for,qcom-display)/libgralloc + LOCAL_C_INCLUDES += $(call project-path-for,qcom-display)/libqdutils + LOCAL_SHARED_LIBRARIES += libqdutils + LOCAL_CFLAGS += -DQTI_BSP + LOCAL_SRC_FILES += \ + ExSurfaceFlinger/ExLayer.cpp \ + ExSurfaceFlinger/ExSurfaceFlinger.cpp \ + ExSurfaceFlinger/ExVirtualDisplaySurface.cpp \ + ExSurfaceFlinger/ExHWComposer.cpp +endif + +ifeq ($(TARGET_HAVE_UI_BLUR),true) + LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/ui + LOCAL_SHARED_LIBRARIES += libuiblur + LOCAL_CFLAGS += -DUI_BLUR +endif + LOCAL_MODULE := libsurfaceflinger LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code @@ -122,6 +146,10 @@ LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--e LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\" LOCAL_CPPFLAGS := -std=c++11 +ifneq ($(ENABLE_CPUSETS),) + LOCAL_CFLAGS += -DENABLE_CPUSETS +endif + LOCAL_SRC_FILES := \ main_surfaceflinger.cpp diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp index 3738a55..73b3897 100644 --- a/services/surfaceflinger/DispSync.cpp +++ b/services/surfaceflinger/DispSync.cpp @@ -21,6 +21,7 @@ #include <math.h> +#include <cutils/iosched_policy.h> #include <cutils/log.h> #include <ui/Fence.h> @@ -292,6 +293,7 @@ DispSync::DispSync() : mThread(new DispSyncThread()) { mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); + android_set_rt_ioprio(mThread->getTid(), 1); reset(); beginResync(); diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h index 67142b6..ebe19a5 100644 --- a/services/surfaceflinger/DispSync.h +++ b/services/surfaceflinger/DispSync.h @@ -26,11 +26,8 @@ namespace android { // Ignore present (retire) fences if the device doesn't have support for the -// sync framework, or if all phase offsets are zero. The latter is useful -// because it allows us to avoid resync bursts on devices that don't need -// phase-offset VSYNC events. -#if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK) || \ - (VSYNC_EVENT_PHASE_OFFSET_NS == 0 && SF_VSYNC_EVENT_PHASE_OFFSET_NS == 0) +// sync framework. +#if defined(RUNNING_WITHOUT_SYNC_FRAMEWORK) static const bool kIgnorePresentFences = true; #else static const bool kIgnorePresentFences = false; diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 13d44f3..f597b73 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -88,21 +88,23 @@ DisplayDevice::DisplayDevice( mPowerMode(HWC_POWER_MODE_OFF), mActiveConfig(0) { - mNativeWindow = new Surface(producer, false); + Surface* surface; + mNativeWindow = surface = new Surface(producer, false); ANativeWindow* const window = mNativeWindow.get(); + char property[PROPERTY_VALUE_MAX]; /* * Create our display's surface */ - EGLSurface surface; + EGLSurface eglSurface; EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (config == EGL_NO_CONFIG) { config = RenderEngine::chooseEglConfig(display, format); } - surface = eglCreateWindowSurface(display, config, window, NULL); - eglQuerySurface(display, surface, EGL_WIDTH, &mDisplayWidth); - eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight); + eglSurface = eglCreateWindowSurface(display, config, window, NULL); + eglQuerySurface(display, eglSurface, EGL_WIDTH, &mDisplayWidth); + eglQuerySurface(display, eglSurface, EGL_HEIGHT, &mDisplayHeight); // Make sure that composition can never be stalled by a virtual display // consumer that isn't processing buffers fast enough. We have to do this @@ -116,7 +118,7 @@ DisplayDevice::DisplayDevice( mConfig = config; mDisplay = display; - mSurface = surface; + mSurface = eglSurface; mFormat = format; mPageFlipCount = 0; mViewport.makeInvalid(); @@ -140,8 +142,17 @@ DisplayDevice::DisplayDevice( break; } + mPanelInverseMounted = false; + // Check if panel is inverse mounted (contents show up HV flipped) + property_get("persist.panel.inversemounted", property, "0"); + mPanelInverseMounted = !!atoi(property); + // initialize the display orientation transform. setProjection(DisplayState::eOrientationDefault, mViewport, mFrame); + +#ifdef NUM_FRAMEBUFFER_SURFACE_BUFFERS + surface->allocateBuffers(); +#endif } DisplayDevice::~DisplayDevice() { @@ -386,6 +397,20 @@ status_t DisplayDevice::orientationToTransfrom( int orientation, int w, int h, Transform* tr) { uint32_t flags = 0; + char value[PROPERTY_VALUE_MAX]; + property_get("ro.sf.hwrotation", value, "0"); + int additionalRot = atoi(value); + + if (additionalRot) { + additionalRot /= 90; + if (orientation == DisplayState::eOrientationUnchanged) { + orientation = additionalRot; + } else { + orientation += additionalRot; + orientation %= 4; + } + } + switch (orientation) { case DisplayState::eOrientationDefault: flags = Transform::ROT_0; @@ -402,6 +427,11 @@ status_t DisplayDevice::orientationToTransfrom( default: return BAD_VALUE; } + + if (DISPLAY_PRIMARY == mHwcDisplayId && isPanelInverseMounted()) { + flags = flags ^ Transform::ROT_180; + } + tr->set(flags, w, h); return NO_ERROR; } @@ -441,7 +471,15 @@ void DisplayDevice::setProjection(int orientation, if (!frame.isValid()) { // the destination frame can be invalid if it has never been set, // in that case we assume the whole display frame. - frame = Rect(w, h); + char value[PROPERTY_VALUE_MAX]; + property_get("ro.sf.hwrotation", value, "0"); + int additionalRot = atoi(value); + + if (additionalRot == 90 || additionalRot == 270) { + frame = Rect(h, w); + } else { + frame = Rect(w, h); + } } if (viewport.isEmpty()) { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 8695a44..f492a42 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -126,6 +126,10 @@ public: int32_t getHwcDisplayId() const { return mHwcDisplayId; } const wp<IBinder>& getDisplayToken() const { return mDisplayToken; } + bool isPanelInverseMounted() const { + return mPanelInverseMounted; + } + // 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; @@ -209,7 +213,7 @@ private: /* * Transaction state */ - static status_t orientationToTransfrom(int orientation, + status_t orientationToTransfrom(int orientation, int w, int h, Transform* tr); uint32_t mLayerStack; @@ -226,6 +230,8 @@ private: int mPowerMode; // Current active config int mActiveConfig; + // Panel is inverse mounted + int mPanelInverseMounted; }; }; // namespace android diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 6ef3295..70af656 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -67,6 +67,7 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp, mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp)); mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp)); mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); + mConsumer->setMaxAcquiredBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS - 1); } status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 0859149..a43597a 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -36,6 +36,9 @@ #include <hardware/hardware.h> #include <hardware/hwcomposer.h> +#ifdef QTI_BSP +#include <hardware/display_defs.h> +#endif #include <android/configuration.h> @@ -190,6 +193,11 @@ HWComposer::HWComposer( // we don't have VSYNC support, we need to fake it mVSyncThread = new VSyncThread(*this); } + + mDimComp = 0; + if (mHwc) { + mHwc->query(mHwc, HWC_BACKGROUND_LAYER_SUPPORTED, &mDimComp); + } } HWComposer::~HWComposer() { @@ -368,7 +376,12 @@ status_t HWComposer::queryDisplayProperties(int disp) { return err; } - mDisplayData[disp].currentConfig = 0; + int currentConfig = getActiveConfig(disp); + if (currentConfig < 0 || currentConfig > static_cast<int>((numConfigs-1))) { + ALOGE("%s: Invalid display config! %d", __FUNCTION__, currentConfig); + currentConfig = 0; + } + mDisplayData[disp].currentConfig = currentConfig; for (size_t c = 0; c < numConfigs; ++c) { err = mHwc->getDisplayAttributes(mHwc, disp, configs[c], DISPLAY_ATTRIBUTES, values); @@ -701,13 +714,14 @@ status_t HWComposer::prepare() { 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]; + for (size_t j=0 ; j<disp.list->numHwLayers ; j++) { + hwc_layer_1_t& l = disp.list->hwLayers[j]; //ALOGD("prepare: %d, type=%d, handle=%p", // i, l.compositionType, l.handle); - if (l.flags & HWC_SKIP_LAYER) { + if ((i == DisplayDevice::DISPLAY_PRIMARY) && + l.flags & HWC_SKIP_LAYER) { l.compositionType = HWC_FRAMEBUFFER; } if (l.compositionType == HWC_FRAMEBUFFER) { @@ -716,6 +730,9 @@ status_t HWComposer::prepare() { if (l.compositionType == HWC_OVERLAY) { disp.hasOvComp = true; } + if (isCompositionTypeBlit(l.compositionType)) { + disp.hasFbComp = true; + } if (l.compositionType == HWC_CURSOR_OVERLAY) { disp.hasOvComp = true; } @@ -816,15 +833,31 @@ status_t HWComposer::setPowerMode(int disp, int mode) { 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); + status_t status = static_cast<status_t>( + mHwc->setActiveConfig(mHwc, disp, mode)); + if (status == NO_ERROR) { + dd.currentConfig = mode; + } else { + ALOGE("%s Failed to set new config (%d) for display (%d)", + __FUNCTION__, mode, disp); + } + return status; } else { LOG_FATAL_IF(mode != 0); } return NO_ERROR; } +int HWComposer::getActiveConfig(int disp) const { + LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE); + if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) { + return mHwc->getActiveConfig(mHwc, disp); + } else { + return 0; + } +} + void HWComposer::disconnectDisplay(int disp) { LOG_ALWAYS_FATAL_IF(disp < 0 || disp == HWC_DISPLAY_PRIMARY); DisplayData& dd(mDisplayData[disp]); @@ -977,6 +1010,17 @@ public: } } } + virtual void setAnimating(bool animating) { + if (animating) { +#ifdef QTI_BSP + getLayer()->flags |= HWC_SCREENSHOT_ANIMATOR_LAYER; +#endif + } else { +#ifdef QTI_BSP + getLayer()->flags &= ~HWC_SCREENSHOT_ANIMATOR_LAYER; +#endif + } + } virtual void setDefaultState() { hwc_layer_1_t* const l = getLayer(); l->compositionType = HWC_FRAMEBUFFER; @@ -998,6 +1042,10 @@ public: getLayer()->flags &= ~HWC_SKIP_LAYER; } } + virtual void setDim() { + setSkip(false); + getLayer()->flags |= 0x80000000; + } virtual void setIsCursorLayerHint(bool isCursor) { if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) { if (isCursor) { @@ -1233,7 +1281,7 @@ void HWComposer::dump(String8& result) const { 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], + (isCompositionTypeBlit(l.compositionType)) ? "HWC_BLIT" : 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, @@ -1241,7 +1289,7 @@ void HWComposer::dump(String8& result) const { } else { result.appendFormat( " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7d,%7d,%7d,%7d |%5d,%5d,%5d,%5d | %s\n", - compositionTypeName[type], + (isCompositionTypeBlit(l.compositionType)) ? "HWC_BLIT" : 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, diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 5e0b3d8..9bdb7de 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -74,7 +74,7 @@ public: const sp<SurfaceFlinger>& flinger, EventHandler& handler); - ~HWComposer(); + virtual ~HWComposer(); status_t initCheck() const; @@ -103,6 +103,9 @@ public: // set active config status_t setActiveConfig(int disp, int mode); + // get active config + int getActiveConfig(int disp) const; + // reset state when an external, non-virtual display is disconnected void disconnectDisplay(int disp); @@ -117,6 +120,9 @@ public: // does this display have layers handled by GLES bool hasGlesComposition(int32_t id) const; + // does this display support dim layer composition + bool hasDimComposition() const { return (mDimComp == 1); } + // 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); @@ -162,6 +168,7 @@ public: virtual sp<Fence> getAndResetReleaseFence() = 0; virtual void setDefaultState() = 0; virtual void setSkip(bool skip) = 0; + virtual void setDim() = 0; virtual void setIsCursorLayerHint(bool isCursor = true) = 0; virtual void setBlending(uint32_t blending) = 0; virtual void setTransform(uint32_t transform) = 0; @@ -174,6 +181,7 @@ public: virtual void setAcquireFenceFd(int fenceFd) = 0; virtual void setPlaneAlpha(uint8_t alpha) = 0; virtual void onDisplayed() = 0; + virtual void setAnimating(bool animating)= 0; }; /* @@ -302,6 +310,14 @@ public: // for debugging ---------------------------------------------------------- void dump(String8& out) const; + /* ------------------------------------------------------------------------ + * Extensions + */ + virtual inline bool isVDSEnabled() const { return true; }; + virtual inline bool isCompositionTypeBlit(const int32_t /*compType*/) const { + return false; + }; + private: void loadHwcModule(); int loadFbHalModule(); @@ -372,6 +388,8 @@ private: // thread-safe mutable Mutex mEventControlLock; + + int mDimComp; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index ba4c198..5fd2136 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -19,6 +19,7 @@ #include "HWComposer.h" #include <gui/BufferItem.h> +#include <gui/Surface.h> // --------------------------------------------------------------------------- namespace android { @@ -30,6 +31,10 @@ static const bool sForceHwcCopy = true; static const bool sForceHwcCopy = false; #endif +#ifndef NUM_FRAMEBUFFER_SURFACE_BUFFERS +#define NUM_FRAMEBUFFER_SURFACE_BUFFERS (2) +#endif + #define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \ mDisplayName.string(), ##__VA_ARGS__) #define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \ @@ -64,6 +69,7 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, { mSource[SOURCE_SINK] = sink; mSource[SOURCE_SCRATCH] = bqProducer; + sp<Surface> surface(new Surface(bqProducer, false)); resetPerFrameState(); @@ -92,7 +98,9 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, mConsumer->setConsumerName(ConsumerBase::mName); mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight); - mConsumer->setDefaultMaxBufferCount(2); + mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); + + surface->allocateBuffers(); } VirtualDisplaySurface::~VirtualDisplaySurface() { @@ -152,7 +160,7 @@ status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { // format/usage and get a new buffer when the GLES driver calls // dequeueBuffer(). mOutputFormat = mDefaultOutputFormat; - mOutputUsage = GRALLOC_USAGE_HW_COMPOSER; + setOutputUsage(GRALLOC_USAGE_HW_COMPOSER); refreshOutputBuffer(); } @@ -377,7 +385,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, bool mSinkBufferWidth, mSinkBufferHeight, buf->getPixelFormat(), buf->getUsage()); mOutputFormat = format; - mOutputUsage = usage; + setOutputUsage(usage); result = refreshOutputBuffer(); if (result < 0) return result; @@ -616,6 +624,10 @@ const char* VirtualDisplaySurface::dbgSourceStr(Source s) { } } +void VirtualDisplaySurface::setOutputUsage(uint32_t usage) { + mOutputUsage = usage; +} + // --------------------------------------------------------------------------- } // namespace android // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 6298751..3d0e412 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -72,6 +72,10 @@ class VirtualDisplaySurface : public DisplaySurface, public BnGraphicBufferProducer, private ConsumerBase { public: +#ifdef QTI_BSP + friend class ExVirtualDisplaySurface; +#endif + VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, const sp<IGraphicBufferProducer>& sink, const sp<IGraphicBufferProducer>& bqProducer, @@ -118,6 +122,7 @@ private: virtual status_t allowAllocation(bool allow); virtual status_t setGenerationNumber(uint32_t generationNumber); virtual String8 getConsumerName() const override; + virtual void setOutputUsage(uint32_t flag); // // Utility methods diff --git a/services/surfaceflinger/DisplayUtils.cpp b/services/surfaceflinger/DisplayUtils.cpp new file mode 100644 index 0000000..a07e69e --- /dev/null +++ b/services/surfaceflinger/DisplayUtils.cpp @@ -0,0 +1,192 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/Log.h> + +#include <gui/Surface.h> +#include <ui/GraphicBuffer.h> + +#include "RenderEngine/RenderEngine.h" +#include "DisplayHardware/FramebufferSurface.h" +#include "DisplayUtils.h" +#ifdef QTI_BSP +#include <ExSurfaceFlinger/ExSurfaceFlinger.h> +#include <ExSurfaceFlinger/ExLayer.h> +#include <ExSurfaceFlinger/ExHWComposer.h> +#include <ExSurfaceFlinger/ExVirtualDisplaySurface.h> +#include <gralloc_priv.h> +#endif +#include <dlfcn.h> +#include <cutils/properties.h> + +namespace android { + +DisplayUtils* DisplayUtils::sDisplayUtils = NULL; +bool DisplayUtils::sUseExtendedImpls = false; + +DisplayUtils::DisplayUtils() { +#ifdef QTI_BSP + sUseExtendedImpls = true; +#endif +} + +DisplayUtils* DisplayUtils::getInstance() { + if(sDisplayUtils == NULL) { + sDisplayUtils = new DisplayUtils(); + } + return sDisplayUtils; +} + +SurfaceFlinger* DisplayUtils::getSFInstance() { +#ifdef QTI_BSP + if(sUseExtendedImpls) { + return new ExSurfaceFlinger(); + } +#endif + return new SurfaceFlinger(); +} + +Layer* DisplayUtils::getLayerInstance(SurfaceFlinger* flinger, + const sp<Client>& client, const String8& name, + uint32_t w, uint32_t h, uint32_t flags) { +#ifdef QTI_BSP + if(sUseExtendedImpls) { + return new ExLayer(flinger, client, name, w, h, flags); + } +#endif + return new Layer(flinger, client, name, w, h, flags); +} + +HWComposer* DisplayUtils::getHWCInstance( + const sp<SurfaceFlinger>& flinger, + HWComposer::EventHandler& handler) { +#ifdef QTI_BSP + if(sUseExtendedImpls) { + return new ExHWComposer(flinger, handler); + } +#endif + return new HWComposer(flinger,handler); +} + +void DisplayUtils::initVDSInstance(HWComposer* hwc, int32_t hwcDisplayId, + sp<IGraphicBufferProducer> currentStateSurface, sp<DisplaySurface> &dispSurface, + sp<IGraphicBufferProducer> &producer, sp<IGraphicBufferProducer> bqProducer, + sp<IGraphicBufferConsumer> bqConsumer, String8 currentStateDisplayName, + bool currentStateIsSecure, int currentStateType) +{ +#ifdef QTI_BSP + if(sUseExtendedImpls) { + if(hwc->isVDSEnabled()) { + VirtualDisplaySurface* vds = new ExVirtualDisplaySurface(*hwc, hwcDisplayId, + currentStateSurface, bqProducer, bqConsumer, currentStateDisplayName, + currentStateIsSecure); + dispSurface = vds; + producer = vds; + } else if(!createV4L2BasedVirtualDisplay(hwc, hwcDisplayId, dispSurface, producer, + currentStateSurface, bqProducer, bqConsumer, currentStateType)) { + VirtualDisplaySurface* vds = new VirtualDisplaySurface(*hwc, hwcDisplayId, + currentStateSurface, bqProducer, bqConsumer, currentStateDisplayName); + dispSurface = vds; + producer = vds; + } + } else { +#endif + (void)currentStateIsSecure; + (void)currentStateType; + VirtualDisplaySurface* vds = new VirtualDisplaySurface(*hwc, hwcDisplayId, + currentStateSurface, bqProducer, bqConsumer, currentStateDisplayName); + dispSurface = vds; + producer = vds; +#ifdef QTI_BSP + } +#endif +} + +bool DisplayUtils::createV4L2BasedVirtualDisplay(HWComposer* hwc, int32_t &hwcDisplayId, + sp<DisplaySurface> &dispSurface, sp<IGraphicBufferProducer> &producer, + sp<IGraphicBufferProducer> currentStateSurface, + sp<IGraphicBufferProducer> bqProducer, sp<IGraphicBufferConsumer> bqConsumer, + int currentStateType) { + char value[PROPERTY_VALUE_MAX]; + property_get("persist.sys.wfd.virtual", value, "0"); + int wfdVirtual = atoi(value); + if(wfdVirtual && hwcDisplayId > 0) { + //Read virtual display properties and create a + //rendering surface for it inorder to be handled + //by hwc. + + sp<ANativeWindow> mNativeWindow = new Surface(currentStateSurface); + ANativeWindow* const window = mNativeWindow.get(); + + int format; + window->query(window, NATIVE_WINDOW_FORMAT, &format); + EGLSurface surface; + EGLint w, h; + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + // In M AOSP getEGLConfig() always returns EGL_NO_CONFIG as + // EGL_ANDROIDX_no_config_context active now. + EGLConfig config = RenderEngine::chooseEglConfig(display, format); + + surface = eglCreateWindowSurface(display, config, window, NULL); + eglQuerySurface(display, surface, EGL_WIDTH, &w); + eglQuerySurface(display, surface, EGL_HEIGHT, &h); + if(hwc->setVirtualDisplayProperties(hwcDisplayId, w, h, format) != NO_ERROR) + return false; + + dispSurface = new FramebufferSurface(*hwc, currentStateType, bqConsumer); + producer = bqProducer; + return true; + } + return false; +} + +bool DisplayUtils::canAllocateHwcDisplayIdForVDS(int usage) { + // on AOSP builds with QTI_BSP disabled, we should allocate hwc display id for virtual display + int flag_mask = 0xffffffff; + +#ifdef QTI_BSP +#ifdef FORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS + // Reserve hardware acceleration for WFD use-case + flag_mask = GRALLOC_USAGE_PRIVATE_WFD; +#else + // Don't allocate HWC display unless we force HWC copy, otherwise + // incompatible buffers are sent to the media stack + flag_mask = 0; +#endif +#endif + + return (usage & flag_mask); +} + +}; // namespace android + diff --git a/services/surfaceflinger/DisplayUtils.h b/services/surfaceflinger/DisplayUtils.h new file mode 100644 index 0000000..bb3d16b --- /dev/null +++ b/services/surfaceflinger/DisplayUtils.h @@ -0,0 +1,79 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ANDROID_DISPLAY_UTILS_H +#define ANDROID_DISPLAY_UTILS_H + +#include <stdint.h> +#include <sys/types.h> + +#include "Layer.h" +#include "SurfaceFlinger.h" +#include "DisplayHardware/HWComposer.h" +#include "DisplayHardware/VirtualDisplaySurface.h" + +// --------------------------------------------------------------------------- + +namespace android { + +class IGraphicBufferProducer; +class IGraphicBufferConsumer; +class DisplaySurface; + +/* Factory Classes */ + +class DisplayUtils { + public: + static DisplayUtils* getInstance() ANDROID_API; + SurfaceFlinger* getSFInstance() ANDROID_API; + Layer* getLayerInstance(SurfaceFlinger*, const sp<Client>&, + const String8&, uint32_t, + uint32_t, uint32_t); + HWComposer* getHWCInstance(const sp<SurfaceFlinger>& flinger, + HWComposer::EventHandler& handler); + void initVDSInstance(HWComposer* hwc, int32_t hwcDisplayId, + sp<IGraphicBufferProducer> currentStateSurface, sp<DisplaySurface> &dispSurface, + sp<IGraphicBufferProducer> &producer, sp<IGraphicBufferProducer> bqProducer, + sp<IGraphicBufferConsumer> bqConsumer, String8 currentStateDisplayName, + bool currentStateIsSecure, int currentStateType); + bool canAllocateHwcDisplayIdForVDS(int usage); + DisplayUtils(); + private: + static DisplayUtils* sDisplayUtils; + static bool sUseExtendedImpls; + + bool createV4L2BasedVirtualDisplay(HWComposer* hwc, int32_t &hwcDisplayId, + sp<DisplaySurface> &dispSurface, sp<IGraphicBufferProducer> &producer, + sp<IGraphicBufferProducer> currentStateSurface, + sp<IGraphicBufferProducer> bqProducer, + sp<IGraphicBufferConsumer> bqConsumer, int currentStateType); +}; + +}; // namespace android + +#endif // ANDROID_DISPLAY_UTILS_H diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index f760200..973a8bc 100644 --- a/services/surfaceflinger/EventThread.cpp +++ b/services/surfaceflinger/EventThread.cpp @@ -20,6 +20,7 @@ #include <sys/types.h> #include <cutils/compiler.h> +#include <cutils/iosched_policy.h> #include <gui/BitTube.h> #include <gui/IDisplayEventConnection.h> @@ -91,6 +92,7 @@ void EventThread::sendVsyncHintOnLocked() { void EventThread::onFirstRef() { run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); + android_set_rt_ioprio(getTid(), 1); } sp<EventThread::Connection> EventThread::createEventConnection() const { diff --git a/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.cpp b/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.cpp new file mode 100644 index 0000000..2b41098 --- /dev/null +++ b/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.cpp @@ -0,0 +1,77 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ExSurfaceFlinger.h" +#include "ExLayer.h" +#include "ExHWComposer.h" +#ifdef QTI_BSP +#include <hardware/display_defs.h> +#endif + +namespace android { + +ExHWComposer::ExHWComposer(const sp<SurfaceFlinger>& flinger, + EventHandler& handler) + : HWComposer(flinger, handler) { + + mVDSEnabled = false; + char property[PROPERTY_VALUE_MAX] = {0}; + + /* Read system property for VDS solution. + * This property is expected to be setup once during bootup + */ + if( (property_get("persist.hwc.enable_vds", property, NULL) > 0) && + ((!strncmp(property, "1", strlen("1"))) || + !strncasecmp(property, "true", strlen("true")))) { + /* HAL virtual display is using VDS based implementation */ + mVDSEnabled = true; + } + + mDebugLogs = false; + if((property_get("persist.debug.qdframework.logs", property, NULL) > 0) && + (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || + (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { + mDebugLogs = true; + } + + ALOGD_IF(isDebug(),"Creating custom HWC %s",__FUNCTION__); +} + +ExHWComposer::~ExHWComposer() { +} + +bool ExHWComposer::isCompositionTypeBlit(const int32_t compType) const { +#ifdef QTI_BSP + return (compType == HWC_BLIT); +#else + ALOGD_IF(mDebugLogs, "%s: compType = %d", __FUNCTION__, compType); +#endif + return false; +} + +}; // namespace android diff --git a/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.h b/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.h new file mode 100644 index 0000000..2016ff0 --- /dev/null +++ b/services/surfaceflinger/ExSurfaceFlinger/ExHWComposer.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ANDROID_EX_HWCOMPOSER_H +#define ANDROID_EX_HWCOMPOSER_H + +#include <DisplayHardware/HWComposer.h> + +namespace android { + +class ExHWComposer : public HWComposer +{ +public: + + ExHWComposer( + const sp<SurfaceFlinger>& flinger, + EventHandler& handler); + + virtual ~ExHWComposer(); + +protected: + bool mVDSEnabled; + inline bool isVDSEnabled() const { return mVDSEnabled; }; + bool mDebugLogs; + bool isDebug() { return mDebugLogs; } + bool isCompositionTypeBlit(const int32_t compType) const; +}; + + +}; //namespace android + +#endif //ANDROID_EX_HWCOMPOSER_H diff --git a/services/surfaceflinger/ExSurfaceFlinger/ExLayer.cpp b/services/surfaceflinger/ExSurfaceFlinger/ExLayer.cpp new file mode 100644 index 0000000..fa45579 --- /dev/null +++ b/services/surfaceflinger/ExSurfaceFlinger/ExLayer.cpp @@ -0,0 +1,207 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/Log.h> + +#include <ui/GraphicBuffer.h> +#ifdef QTI_BSP +#include <gralloc_priv.h> +#include <hardware/display_defs.h> +#endif + +#include "ExLayer.h" + +namespace android { + +/* Calculates the aspect ratio for external display based on the video w/h */ +static Rect getAspectRatio(const sp<const DisplayDevice>& hw, + const int& srcWidth, const int& srcHeight) { + Rect outRect; + int fbWidth = hw->getWidth(); + int fbHeight = hw->getHeight(); + int x , y = 0; + int w = fbWidth, h = fbHeight; + if (srcWidth * fbHeight > fbWidth * srcHeight) { + h = fbWidth * srcHeight / srcWidth; + w = fbWidth; + } else if (srcWidth * fbHeight < fbWidth * srcHeight) { + w = fbHeight * srcWidth / srcHeight; + h = fbHeight; + } + x = (fbWidth - w) / 2; + y = (fbHeight - h) / 2; + outRect.left = x; + outRect.top = y; + outRect.right = x + w; + outRect.bottom = y + h; + + return outRect; +} + +ExLayer::ExLayer(SurfaceFlinger* flinger, const sp<Client>& client, + const String8& name, uint32_t w, uint32_t h, uint32_t flags) + : Layer(flinger, client, name, w, h, flags) { + + char property[PROPERTY_VALUE_MAX] = {0}; + + mDebugLogs = false; + mIsGPUAllowedForProtected = false; + if((property_get("persist.debug.qdframework.logs", property, NULL) > 0) && + (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || + (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { + mDebugLogs = true; + } + + ALOGD_IF(isDebug(),"Creating custom Layer %s",__FUNCTION__); + + if ((property_get("persist.gralloc.cp.level3", property, NULL) > 0) && + (atoi(property) == 1)) { + mIsGPUAllowedForProtected = true; + } +} + +ExLayer::~ExLayer() { +} + +bool ExLayer::isExtOnly() const { + const sp<GraphicBuffer>& activeBuffer(mActiveBuffer); + if (activeBuffer != 0) { +#ifdef QTI_BSP + ANativeWindowBuffer* buffer = activeBuffer->getNativeBuffer(); + if(buffer) { + private_handle_t* hnd = static_cast<private_handle_t*> + (const_cast<native_handle_t*>(buffer->handle)); + /* return true if layer is EXT_ONLY */ + return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY)); + } +#endif + } + return false; +} + +bool ExLayer::isIntOnly() const { + const sp<GraphicBuffer>& activeBuffer(mActiveBuffer); + if (activeBuffer != 0) { +#ifdef QTI_BSP + ANativeWindowBuffer* buffer = activeBuffer->getNativeBuffer(); + if(buffer) { + private_handle_t* hnd = static_cast<private_handle_t*> + (const_cast<native_handle_t*>(buffer->handle)); + /* return true if layer is INT_ONLY */ + return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_INTERNAL_ONLY)); + } +#endif + } + return false; +} + +bool ExLayer::isSecureDisplay() const { + const sp<GraphicBuffer>& activeBuffer(mActiveBuffer); + if (activeBuffer != 0) { +#ifdef QTI_BSP + ANativeWindowBuffer* buffer = activeBuffer->getNativeBuffer(); + if(buffer) { + private_handle_t* hnd = static_cast<private_handle_t*> + (const_cast<native_handle_t*>(buffer->handle)); + /* return true if layer is SECURE_DISPLAY */ + return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY)); + } +#endif + } + return false; +} + +bool ExLayer::isYuvLayer() const { + const sp<GraphicBuffer>& activeBuffer(mActiveBuffer); + if(activeBuffer != 0) { +#ifdef QTI_BSP + ANativeWindowBuffer* buffer = activeBuffer->getNativeBuffer(); + if(buffer) { + private_handle_t* hnd = static_cast<private_handle_t*> + (const_cast<native_handle_t*>(buffer->handle)); + /* return true if layer is YUV */ + return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO)); + } +#endif + } + return false; +} + +void ExLayer::setPosition(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer, const State& state) { + /* Set dest_rect to display width and height, if external_only flag + * for the layer is enabled or if its yuvLayer in extended mode. + */ + uint32_t w = hw->getWidth(); + uint32_t h = hw->getHeight(); + bool extendedMode = ExSurfaceFlinger::isExtendedMode(); + if(isExtOnly()) { + /* Position: fullscreen for ext_only */ + Rect r(0, 0, w, h); + layer.setFrame(r); + } else if(hw->getDisplayType() > 0 && (extendedMode && isYuvLayer())) { + /* Need to position the video full screen on external with aspect ratio */ + Rect r = getAspectRatio(hw, state.active.w, state.active.h); + layer.setFrame(r); + } + return; +} + +void ExLayer::setAcquiredFenceIfBlit(int &fenceFd, + HWComposer::HWCLayerInterface& layer) { +#ifdef QTI_BSP + if (layer.getCompositionType() == HWC_BLIT) { + sp<Fence> fence = mSurfaceFlingerConsumer->getCurrentFence(); + if (fence->isValid()) { + fenceFd = fence->dup(); + if (fenceFd == -1) { + ALOGW("%s: failed to dup layer fence, skipping sync: %d", + __FUNCTION__,errno); + } + } + } +#else + ALOGD_IF(isDebug(),"Not a BLIT Layer, compType = %d fencefd = %d", + layer.getCompositionType(), fenceFd); +#endif +} + +bool ExLayer::canAllowGPUForProtected() const { + if(isProtected()) { + return mIsGPUAllowedForProtected; + } else { + return false; + } +} + +}; // namespace android diff --git a/services/surfaceflinger/ExSurfaceFlinger/ExLayer.h b/services/surfaceflinger/ExSurfaceFlinger/ExLayer.h new file mode 100644 index 0000000..01c74a8 --- /dev/null +++ b/services/surfaceflinger/ExSurfaceFlinger/ExLayer.h @@ -0,0 +1,68 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ANDROID_EX_LAYER_H +#define ANDROID_EX_LAYER_H + +#include <stdint.h> +#include <sys/types.h> +#include <cutils/properties.h> + +#include <Layer.h> +#include "ExSurfaceFlinger.h" + +namespace android { + +class ExSurfaceFlinger; + +class ExLayer : public Layer +{ +public: + ExLayer(SurfaceFlinger* flinger, const sp<Client>& client, + const String8& name, uint32_t w, uint32_t h, uint32_t flags); + virtual ~ExLayer(); + + virtual bool isExtOnly() const; + virtual bool isIntOnly() const; + virtual bool isSecureDisplay() const; + virtual bool isYuvLayer() const; + virtual void setPosition(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer, const State& state); + virtual void setAcquiredFenceIfBlit(int &fenceFd, + HWComposer::HWCLayerInterface& layer); + virtual bool canAllowGPUForProtected() const; + +protected: + bool mDebugLogs; + bool isDebug() { return mDebugLogs; } + bool mIsGPUAllowedForProtected; +}; + +}; // namespace android + +#endif // ANDROID_EX_LAYER_H diff --git a/services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.cpp b/services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.cpp new file mode 100644 index 0000000..96d4b1d --- /dev/null +++ b/services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.cpp @@ -0,0 +1,376 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ExSurfaceFlinger.h" +#include "ExLayer.h" +#include <fstream> +#include <cutils/properties.h> +#ifdef QTI_BSP +#include <hardware/display_defs.h> +#endif +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +namespace android { + +bool ExSurfaceFlinger::sExtendedMode = false; + +ExSurfaceFlinger::ExSurfaceFlinger() { + char property[PROPERTY_VALUE_MAX] = {0}; + + mDebugLogs = false; + if((property_get("persist.debug.qdframework.logs", property, NULL) > 0) && + (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || + (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { + mDebugLogs = true; + } + + ALOGD_IF(isDebug(),"Creating custom SurfaceFlinger %s",__FUNCTION__); + + mDisableExtAnimation = false; + if((property_get("sys.disable_ext_animation", property, "0") > 0) && + (!strncmp(property, "1", PROPERTY_VALUE_MAX ) || + (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) { + mDisableExtAnimation = true; + } + + ALOGD_IF(isDebug(),"Animation on external is %s in %s", + mDisableExtAnimation ? "disabled" : "not disabled", __FUNCTION__); +} + +ExSurfaceFlinger::~ExSurfaceFlinger() { } + +void ExSurfaceFlinger::updateExtendedMode() { + char prop[PROPERTY_VALUE_MAX]; + property_get("sys.extended_mode", prop, "0"); + sExtendedMode = atoi(prop) ? true : false; +} + +void ExSurfaceFlinger::getIndexLOI(size_t dpy, + const LayerVector& currentLayers, + bool& bIgnoreLayers, + int& indexLOI ) { + size_t i = currentLayers.size(); + while(i--) { + const sp<Layer>& layer = currentLayers[i]; + /* iterate through the layer list to find ext_only layers and store + * the index + */ + if (layer->isSecureDisplay()) { + bIgnoreLayers = true; + indexLOI = -1; + if(!dpy) + indexLOI = i; + break; + } + /* iterate through the layer list to find ext_only layers or yuv + * layer(extended_mode) and store the index + */ + if ((dpy && (layer->isExtOnly() || + (isExtendedMode() && layer->isYuvLayer())))) { + bIgnoreLayers= true; + indexLOI = i; + } + } + return; +} + +bool ExSurfaceFlinger::updateLayerVisibleNonTransparentRegion( + const int& dpy, const sp<Layer>& layer, + bool& bIgnoreLayers, int& indexLOI, + uint32_t layerStack, const int& i) { + + const Layer::State& s(layer->getDrawingState()); + + /* Only add the layer marked as "external_only" or yuvLayer + * (extended_mode) to external list and + * only remove the layer marked as "external_only" or yuvLayer in + * extended_mode from primary list + * and do not add the layer marked as "internal_only" to external list + * Add secure UI layers to primary and remove other layers from internal + * and external list + */ + if(((bIgnoreLayers && indexLOI != (int)i) || + (!dpy && layer->isExtOnly()) || + (!dpy && isExtendedMode() && layer->isYuvLayer()))|| + (dpy && layer->isIntOnly())) { + /* Ignore all other layers except the layers marked as ext_only + * by setting visible non transparent region empty + */ + Region visibleNonTransRegion; + visibleNonTransRegion.set(Rect(0,0)); + layer->setVisibleNonTransparentRegion(visibleNonTransRegion); + return true; + } + /* only consider the layers on the given later stack + * Override layers created using presentation class by the layers having + * ext_only flag enabled + */ + if(s.layerStack != layerStack && !bIgnoreLayers) { + /* set the visible region as empty since we have removed the + * layerstack check in rebuildLayerStack() function + */ + Region visibleNonTransRegion; + visibleNonTransRegion.set(Rect(0,0)); + layer->setVisibleNonTransparentRegion(visibleNonTransRegion); + return true; + } + + if (mDisableExtAnimation) { + /* Remove screenShotSurface from secondary displays when ext animation disabled */ + const int screenShotLen = strlen("ScreenshotSurface"); + if (dpy && !strncmp(layer->getName(), "ScreenshotSurface", screenShotLen) ) { + Region visibleNonTransRegion; + visibleNonTransRegion.set(Rect(0, 0)); + layer->setVisibleNonTransparentRegion(visibleNonTransRegion); + return true; + } + } + + return false; +} + +void ExSurfaceFlinger::delayDPTransactionIfNeeded( + const Vector<DisplayState>& displays) { + /* Delay the display projection transaction by 50ms only when the disable + * external rotation animation feature is enabled + */ + if(mDisableExtAnimation) { + size_t count = displays.size(); + for (size_t i=0 ; i<count ; i++) { + const DisplayState& s(displays[i]); + if((mDisplays.indexOfKey(s.token) >= 0) && (s.token != + mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])) { + const uint32_t what = s.what; + /* Invalidate and Delay the binder thread by 50 ms on + * eDisplayProjectionChanged to trigger a draw cycle so that + * it can fix one incorrect frame on the External, when we + * disable external animation + */ + if (what & DisplayState::eDisplayProjectionChanged) { + invalidateHwcGeometry(); + repaintEverything(); + usleep(50000); + } + } + } + } +} + +bool ExSurfaceFlinger::canDrawLayerinScreenShot( + const sp<const DisplayDevice>& hw, + const sp<Layer>& layer) { + int dispType = hw->getDisplayType(); + /* a) Don't draw SecureDisplayLayer or ProtectedLayer. + * b) Don't let ext_only and extended_mode to be captured + * If not, we would see incorrect image during rotation + * on primary. + */ + if(!layer->isSecureDisplay() + && !layer->isProtected() + && !(!dispType && (layer->isExtOnly() || + (isExtendedMode() && layer->isYuvLayer()))) + && !(layer->isIntOnly() && dispType) + && layer->isVisible()){ + return true; + } + return false; +} + +void ExSurfaceFlinger::isfreezeSurfacePresent(bool& freezeSurfacePresent, + const sp<const DisplayDevice>& hw, + const int32_t& id) { + freezeSurfacePresent = false; + /* Get the layers in the current drawing state */ + const LayerVector& layers(mDrawingState.layersSortedByZ); + const size_t layerCount = layers.size(); + /* Look for ScreenShotSurface in external layer list, only when + * disable external rotation animation feature is enabled + */ + if(mDisableExtAnimation && (id != HWC_DISPLAY_PRIMARY)) { + for (size_t i = 0 ; i < layerCount ; ++i) { + static int screenShotLen = strlen("ScreenshotSurface"); + const sp<Layer>& layer(layers[i]); + const Layer::State& s(layer->getDrawingState()); + /* check the layers associated with external display */ + if(s.layerStack == hw->getLayerStack()) { + if(!strncmp(layer->getName(), "ScreenshotSurface", + screenShotLen)) { + /* Screenshot layer is present, and animation in + * progress + */ + freezeSurfacePresent = true; + break; + } + } + } + } +} + +void ExSurfaceFlinger::setOrientationEventControl(bool& freezeSurfacePresent, + const int32_t& id) { + HWComposer& hwc(getHwComposer()); + HWComposer::LayerListIterator cur = hwc.begin(id); + + if(freezeSurfacePresent) { + /* If freezeSurfacePresent, set ANIMATING flag + * which is used to support disable animation on external + */ + cur->setAnimating(true); + } +} + +void ExSurfaceFlinger::updateVisibleRegionsDirty() { + /* If extended_mode is set, and set mVisibleRegionsDirty + * as we need to rebuildLayerStack + */ + if(isExtendedMode()) { + mVisibleRegionsDirty = true; + } +} + +void ExSurfaceFlinger::drawWormHoleIfRequired(HWComposer::LayerListIterator& cur, + const HWComposer::LayerListIterator& end, + const sp<const DisplayDevice>& hw, + const Region& region) { + if (cur != end) { +#ifdef QTI_BSP + if (cur->getCompositionType() != HWC_BLIT) + drawWormhole(hw, region); +#endif + } else { + drawWormhole(hw, region); + } +} + +#ifdef DEBUG_CONT_DUMPSYS +status_t ExSurfaceFlinger::dump(int fd, const Vector<String16>& args) { + // Format: adb shell dumpsys SurfaceFlinger --file --no-limit + size_t numArgs = args.size(); + status_t err = NO_ERROR; + + if (!numArgs || (args[0] != String16("--file"))) { + return SurfaceFlinger::dump(fd, args); + } + + Mutex::Autolock _l(mFileDump.lock); + + // Same command is used to start and end dump. + mFileDump.running = !mFileDump.running; + + if (mFileDump.running) { + // Create an empty file or erase existing file. + std::fstream fs; + fs.open(mFileDump.name, std::ios::out); + if (!fs) { + mFileDump.running = false; + err = UNKNOWN_ERROR; + } else { + mFileDump.position = 0; + if (numArgs >= 2 && (args[1] == String16("--nolimit"))) { + mFileDump.noLimit = true; + } else { + mFileDump.noLimit = false; + } + } + } + + String8 result; + result += mFileDump.running ? "Start" : "End"; + result += mFileDump.noLimit ? " unlimited" : " fixed limit"; + result += " dumpsys to file : "; + result += mFileDump.name; + result += "\n"; + + write(fd, result.string(), result.size()); + + return NO_ERROR; +} + +void ExSurfaceFlinger::dumpDrawCycle(bool prePrepare) { + Mutex::Autolock _l(mFileDump.lock); + + // User might stop dump collection in middle of prepare & commit. + // Collect dumpsys again after commit and replace. + if (!mFileDump.running && !mFileDump.replaceAfterCommit) { + return; + } + + Vector<String16> args; + size_t index = 0; + String8 dumpsys; + + dumpAllLocked(args, index, dumpsys); + + char timeStamp[32]; + char dataSize[32]; + char hms[32]; + long millis; + struct timeval tv; + struct tm *ptm; + + gettimeofday(&tv, NULL); + ptm = localtime(&tv.tv_sec); + strftime (hms, sizeof (hms), "%H:%M:%S", ptm); + millis = tv.tv_usec / 1000; + snprintf(timeStamp, sizeof(timeStamp), "Timestamp: %s.%03ld", hms, millis); + snprintf(dataSize, sizeof(dataSize), "Size: %8zu", dumpsys.size()); + + std::fstream fs; + fs.open(mFileDump.name, std::ios::in | std::ios::out); + if (!fs) { + ALOGE("Failed to open %s file for dumpsys", mFileDump.name); + return; + } + + // Format: + // | start code | after commit? | time stamp | dump size | dump data | + fs.seekp(mFileDump.position, std::ios::beg); + + fs << "#@#@-- DUMPSYS START --@#@#" << std::endl; + fs << "PostCommit: " << ( prePrepare ? "false" : "true" ) << std::endl; + fs << timeStamp << std::endl; + fs << dataSize << std::endl; + fs << dumpsys << std::endl; + + if (prePrepare) { + mFileDump.replaceAfterCommit = true; + } else { + mFileDump.replaceAfterCommit = false; + // Reposition only after commit. + // Keem file size to appx 20 MB limit by default, wrap around if exceeds. + mFileDump.position = fs.tellp(); + if (!mFileDump.noLimit && (mFileDump.position > (20 * 1024 * 1024))) { + mFileDump.position = 0; + } + } + + fs.close(); +} +#endif + +}; // namespace android diff --git a/services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.h b/services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.h new file mode 100644 index 0000000..068f2b9 --- /dev/null +++ b/services/surfaceflinger/ExSurfaceFlinger/ExSurfaceFlinger.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ANDROID_EX_SURFACE_FLINGER_H +#define ANDROID_EX_SURFACE_FLINGER_H + +#include "SurfaceFlinger.h" + +namespace android { + +class ExSurfaceFlinger : public SurfaceFlinger +{ +public: + + ExSurfaceFlinger(); + +protected: + friend class ExLayer; + + virtual void updateExtendedMode(); + virtual void getIndexLOI(size_t dpy, + const LayerVector& currentLayers, + bool& bIgnoreLayers, + int& indexLOI); + virtual bool updateLayerVisibleNonTransparentRegion( + const int& dpy, const sp<Layer>& layer, + bool& bIgnoreLayers, int& indexLOI, + uint32_t layerStack, const int& i); + virtual void delayDPTransactionIfNeeded( + const Vector<DisplayState>& displays); + virtual bool canDrawLayerinScreenShot( + const sp<const DisplayDevice>& hw, + const sp<Layer>& layer); + virtual void isfreezeSurfacePresent( + bool& freezeSurfacePresent, + const sp<const DisplayDevice>& hw, + const int32_t& id); + virtual void setOrientationEventControl( + bool& freezeSurfacePresent, + const int32_t& id); + virtual void updateVisibleRegionsDirty(); + virtual void drawWormHoleIfRequired(HWComposer::LayerListIterator& /*cur*/, + const HWComposer::LayerListIterator& /*end*/, + const sp<const DisplayDevice>& hw, + const Region& region); + virtual ~ExSurfaceFlinger(); + + /* Extended Mode + * No video on primary but video will be shown full + * screen on External + */ + static bool sExtendedMode; + static bool isExtendedMode() { return sExtendedMode; } + bool mDebugLogs; + bool isDebug() { return mDebugLogs; } + bool mDisableExtAnimation; + +#ifdef DEBUG_CONT_DUMPSYS + virtual status_t dump(int fd, const Vector<String16>& args); + virtual void dumpDrawCycle(bool prePrepare ); + + struct { + Mutex lock; + const char *name = "/data/misc/display/dumpsys.txt"; + bool running = false; + bool noLimit = false; + bool replaceAfterCommit = false; + long int position = 0; + } mFileDump; +#endif +}; + +}; //namespace android + +#endif //ANDROID_EX_SURFACE_FLINGER_H diff --git a/services/surfaceflinger/ExSurfaceFlinger/ExVirtualDisplaySurface.cpp b/services/surfaceflinger/ExSurfaceFlinger/ExVirtualDisplaySurface.cpp new file mode 100644 index 0000000..e4ad758 --- /dev/null +++ b/services/surfaceflinger/ExSurfaceFlinger/ExVirtualDisplaySurface.cpp @@ -0,0 +1,93 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ExVirtualDisplaySurface.h" +#ifdef QTI_BSP +#include <gralloc_priv.h> +#endif + +namespace android { + +#define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \ + mDisplayName.string(), ##__VA_ARGS__) +#define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \ + mDisplayName.string(), ##__VA_ARGS__) +#define VDS_LOGV(msg, ...) ALOGV("[%s] " msg, \ + mDisplayName.string(), ##__VA_ARGS__) + +ExVirtualDisplaySurface::ExVirtualDisplaySurface(HWComposer& hwc, int32_t dispId, + const sp<IGraphicBufferProducer>& sink, + const sp<IGraphicBufferProducer>& bqProducer, + const sp<IGraphicBufferConsumer>& bqConsumer, + const String8& name, + bool secure) +: VirtualDisplaySurface(hwc, dispId, sink, bqProducer, bqConsumer, name), + mSecure(secure) { + sink->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &mSinkUsage); + mSinkUsage |= GRALLOC_USAGE_HW_COMPOSER; + setOutputUsage(mSinkUsage); +} + +status_t ExVirtualDisplaySurface::beginFrame(bool mustRecompose) { + if (mDisplayId < 0) + return NO_ERROR; + + mMustRecompose = mustRecompose; + /* For WFD use cases we must always set the recompose flag in order + * to support pause/resume functionality + */ + if (mOutputUsage & GRALLOC_USAGE_HW_VIDEO_ENCODER) { + mMustRecompose = true; + } + + VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE, + "Unexpected beginFrame() in %s state", dbgStateStr()); + mDbgState = DBG_STATE_BEGUN; + + return refreshOutputBuffer(); + +} + +/* Helper to update the output usage when the display is secure */ +void ExVirtualDisplaySurface::setOutputUsage(uint32_t /*flag*/) { + mOutputUsage = mSinkUsage; + if (mSecure && (mOutputUsage & GRALLOC_USAGE_HW_VIDEO_ENCODER)) { + /* TODO: Currently, the framework can only say whether the display + * and its subsequent session are secure or not. However, there is + * no mechanism to distinguish the different levels of security. + * The current solution assumes WV L3 protection. + */ + mOutputUsage |= GRALLOC_USAGE_PROTECTED; +#ifdef QTI_BSP + mOutputUsage |= GRALLOC_USAGE_PRIVATE_MM_HEAP | + GRALLOC_USAGE_PRIVATE_UNCACHED; +#endif + } +} + +}; // namespace android diff --git a/services/surfaceflinger/ExSurfaceFlinger/ExVirtualDisplaySurface.h b/services/surfaceflinger/ExSurfaceFlinger/ExVirtualDisplaySurface.h new file mode 100644 index 0000000..ab71594 --- /dev/null +++ b/services/surfaceflinger/ExSurfaceFlinger/ExVirtualDisplaySurface.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ANDROID_EX_VIRTUAL_DISPLAY_SURFACE_H +#define ANDROID_EX_VIRTUAL_DISPLAY_SURFACE_H + +#include <DisplayHardware/VirtualDisplaySurface.h> + +namespace android { + +class ExVirtualDisplaySurface : public VirtualDisplaySurface { +public: + ExVirtualDisplaySurface(HWComposer& hwc, int32_t dispId, + const sp<IGraphicBufferProducer>& sink, + const sp<IGraphicBufferProducer>& bqProducer, + const sp<IGraphicBufferConsumer>& bqConsumer, + const String8& name, + bool secure); + +private: + virtual status_t beginFrame(bool mustRecompose); + virtual void setOutputUsage(uint32_t flag); + bool mSecure; + int mSinkUsage; +}; + +}; // namespace android + +#endif // ANDROID_EX_VIRTUAL_DISPLAY_SURFACE_H + diff --git a/services/surfaceflinger/FrameRateHelper.h b/services/surfaceflinger/FrameRateHelper.h new file mode 100644 index 0000000..1a69fed --- /dev/null +++ b/services/surfaceflinger/FrameRateHelper.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ANDROID_SF_FRAME_RATE_HELPER_H +#define ANDROID_SF_FRAME_RATE_HELPER_H + +#include <utils/Timers.h> + +namespace android { + +class FrameRateHelper { +public: + FrameRateHelper() : mTime(0), mFps(0), mFpsCount(0) {} + ~FrameRateHelper() {} + + bool update() { + mFpsCount++; + + nsecs_t now = systemTime(); + if (ns2ms(now - mTime) > 1000) { + mFps = mFpsCount; + mFpsCount = 0; + mTime = now; + return true; + } + + return false; + } + + unsigned int get() const { + return mFps; + } + +private: + nsecs_t mTime; + unsigned int mFps; + unsigned int mFpsCount; +}; + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SF_FRAME_RATE_HELPER_H diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5ff79a9..6dd8bad 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -84,7 +84,8 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mQueueItemCondition(), mQueueItems(), mLastFrameNumberReceived(0), - mUpdateTexImageFailed(false) + mUpdateTexImageFailed(false), + mTransformHint(0) { mCurrentCrop.makeInvalid(); mFlinger->getRenderEngine().genTextures(1, &mTextureName); @@ -108,6 +109,7 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, mCurrentState.active.crop.makeInvalid(); mCurrentState.z = 0; mCurrentState.alpha = 0xFF; + mCurrentState.blur = 0xFF; mCurrentState.layerStack = 0; mCurrentState.flags = layerFlags; mCurrentState.sequence = 0; @@ -320,11 +322,13 @@ Rect Layer::getContentCrop() const { return crop; } -static Rect reduce(const Rect& win, const Region& exclude) { +Rect Layer::reduce(const Rect& win, const Region& exclude) const{ if (CC_LIKELY(exclude.isEmpty())) { return win; } - if (exclude.isRect()) { + Rect tmp; + win.intersect(exclude.getBounds(), &tmp); + if (exclude.isRect() && !tmp.isEmpty()) { return win.reduce(exclude.getBounds()); } return Region(win).subtract(exclude).getBounds(); @@ -494,6 +498,7 @@ void Layer::setGeometry( frame.intersect(hw->getViewport(), &frame); const Transform& tr(hw->getTransform()); layer.setFrame(tr.transform(frame)); + setPosition(hw, layer, s); layer.setCrop(computeCrop(hw)); layer.setPlaneAlpha(s.alpha); @@ -578,6 +583,7 @@ void Layer::setAcquireFence(const sp<const DisplayDevice>& /* hw */, } } } + setAcquiredFenceIfBlit(fenceFd, layer); layer.setAcquireFenceFd(fenceFd); } @@ -605,21 +611,21 @@ Rect Layer::getPosition( // drawing... // --------------------------------------------------------------------------- -void Layer::draw(const sp<const DisplayDevice>& hw, const Region& clip) const { +void Layer::draw(const sp<const DisplayDevice>& hw, const Region& clip) { onDraw(hw, clip, false); } void Layer::draw(const sp<const DisplayDevice>& hw, - bool useIdentityTransform) const { + bool useIdentityTransform) { onDraw(hw, Region(hw->bounds()), useIdentityTransform); } -void Layer::draw(const sp<const DisplayDevice>& hw) const { +void Layer::draw(const sp<const DisplayDevice>& hw) { onDraw(hw, Region(hw->bounds()), false); } void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip, - bool useIdentityTransform) const + bool useIdentityTransform) { ATRACE_CALL(); @@ -663,8 +669,8 @@ void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip, bool blackOutLayer = isProtected() || (isSecure() && !hw->isSecure()); RenderEngine& engine(mFlinger->getRenderEngine()); - - if (!blackOutLayer) { + if (!blackOutLayer || + ((hw->getDisplayType() == HWC_DISPLAY_PRIMARY) && canAllowGPUForProtected())) { // TODO: we could be more subtle with isFixedSize() const bool useFiltering = getFiltering() || needsFiltering(hw) || isFixedSize(); @@ -750,8 +756,19 @@ void Layer::drawWithOpenGL(const sp<const DisplayDevice>& hw, * minimal value)? Or, we could make GL behave like HWC -- but this feel * like more of a hack. */ - const Rect win(computeBounds()); - + Rect win(s.active.w, s.active.h); + if(!s.active.crop.isEmpty()) { + win = s.active.crop; + } +#ifdef QTI_BSP + win = s.transform.transform(win); + win.intersect(hw->getViewport(), &win); + win = s.transform.inverse().transform(win); + win.intersect(Rect(s.active.w, s.active.h), &win); + win = reduce(win, s.activeTransparentRegion); +#else + win = reduce(win, s.activeTransparentRegion); +#endif float left = float(win.left) / float(s.active.w); float top = float(win.top) / float(s.active.h); float right = float(win.right) / float(s.active.w); @@ -818,16 +835,49 @@ void Layer::computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh, bool useIdentityTransform) const { const Layer::State& s(getDrawingState()); - const Transform tr(useIdentityTransform ? + Transform tr(useIdentityTransform ? hw->getTransform() : hw->getTransform() * s.transform); const uint32_t hw_h = hw->getHeight(); Rect win(s.active.w, s.active.h); if (!s.active.crop.isEmpty()) { win.intersect(s.active.crop, &win); } - // subtract the transparent region and snap to the bounds +#ifdef QTI_BSP + win = s.transform.transform(win); + win.intersect(hw->getViewport(), &win); + win = s.transform.inverse().transform(win); + win.intersect(Rect(s.active.w, s.active.h), &win); win = reduce(win, s.activeTransparentRegion); - + const Transform bufferOrientation(mCurrentTransform); + Transform transform(tr * s.transform * bufferOrientation); + if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) { + uint32_t invTransform = hw->getOrientationTransform(); + uint32_t t_orientation = transform.getOrientation(); + if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { + invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | + NATIVE_WINDOW_TRANSFORM_FLIP_H; + bool is_h_flipped = (t_orientation & + NATIVE_WINDOW_TRANSFORM_FLIP_H) != 0; + bool is_v_flipped = (t_orientation & + NATIVE_WINDOW_TRANSFORM_FLIP_V) != 0; + if (is_h_flipped != is_v_flipped) { + t_orientation ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | + NATIVE_WINDOW_TRANSFORM_FLIP_H; + } + transform = Transform(t_orientation) * Transform(invTransform); + } + } + const uint32_t orientation = transform.getOrientation(); + if (!(mTransformHint | mCurrentTransform | orientation)) { + tr = hw->getTransform(); + if (!useIdentityTransform) { + win = s.transform.transform(win); + win.intersect(hw->getViewport(), &win); + } + } +#else + win = reduce(win, s.activeTransparentRegion); +#endif Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); position[0] = tr.transform(win.left, win.top); position[1] = tr.transform(win.left, win.bottom); @@ -1029,6 +1079,14 @@ bool Layer::setLayer(uint32_t z) { setTransactionFlags(eTransactionNeeded); return true; } +bool Layer::setBlur(uint8_t blur) { + if (mCurrentState.blur == blur) + return false; + mCurrentState.sequence++; + mCurrentState.blur = blur; + setTransactionFlags(eTransactionNeeded); + return true; +} bool Layer::setSize(uint32_t w, uint32_t h) { if (mCurrentState.requested.w == w && mCurrentState.requested.h == h) return false; @@ -1440,7 +1498,7 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const return usage; } -void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const { +void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) { uint32_t orientation = 0; if (!mFlinger->mDebugDisableTransformHint) { // The transform hint is used to improve performance, but we can @@ -1453,6 +1511,7 @@ void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const { } } mSurfaceFlingerConsumer->setTransformHint(orientation); + mTransformHint = orientation; } // ---------------------------------------------------------------------------- @@ -1477,13 +1536,13 @@ void Layer::dump(String8& result, Colorizer& colorizer) const result.appendFormat( " " "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), " "isOpaque=%1d, invalidate=%1d, " - "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" + "alpha=0x%02x, blur=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" " client=%p\n", s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h, s.active.crop.left, s.active.crop.top, s.active.crop.right, s.active.crop.bottom, isOpaque(s), contentDirty, - s.alpha, s.flags, + s.alpha, s.blur, s.flags, s.transform[0][0], s.transform[0][1], s.transform[1][0], s.transform[1][1], client.get()); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index c1e5e9f..196ef3e 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -57,6 +57,7 @@ class Colorizer; class DisplayDevice; class GraphicBuffer; class SurfaceFlinger; +class LayerBlur; // --------------------------------------------------------------------------- @@ -70,7 +71,12 @@ class SurfaceFlinger; class Layer : public SurfaceFlingerConsumer::ContentsChangedListener { static int32_t sSequence; + friend class LayerBlur; + public: +#ifdef QTI_BSP + friend class ExLayer; +#endif mutable bool contentDirty; // regions below are in window-manager space Region visibleRegion; @@ -105,6 +111,7 @@ public: Geometry requested; uint32_t z; uint32_t layerStack; + uint8_t blur; uint8_t alpha; uint8_t flags; uint8_t reserved[2]; @@ -130,6 +137,10 @@ public: // modify current state bool setPosition(float x, float y); bool setLayer(uint32_t z); + bool setBlur(uint8_t blur); + virtual bool setBlurMaskLayer(sp<Layer>& /*maskLayer*/) { return false; } + virtual bool setBlurMaskSampling(int32_t /*sampling*/) { return false; } + virtual bool setBlurMaskAlphaThreshold(float /*alpha*/) { return false; } bool setSize(uint32_t w, uint32_t h); bool setAlpha(uint8_t alpha); bool setMatrix(const layer_state_t::matrix22_t& matrix); @@ -192,19 +203,24 @@ public: */ virtual bool isFixedSize() const; + /* + * isBlurLayer - true if this is a LayerBlur instance + */ + virtual bool isBlurLayer() const { return false; } + protected: /* * onDraw - draws the surface. */ virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip, - bool useIdentityTransform) const; + bool useIdentityTransform); public: // ----------------------------------------------------------------------- void setGeometry(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer); - void setPerFrameData(const sp<const DisplayDevice>& hw, + virtual void setPerFrameData(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer); void setAcquireFence(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer); @@ -234,9 +250,9 @@ public: * draw - performs some global clipping optimizations * and calls onDraw(). */ - void draw(const sp<const DisplayDevice>& hw, const Region& clip) const; - void draw(const sp<const DisplayDevice>& hw, bool useIdentityTransform) const; - void draw(const sp<const DisplayDevice>& hw) const; + void draw(const sp<const DisplayDevice>& hw, const Region& clip); + void draw(const sp<const DisplayDevice>& hw, bool useIdentityTransform); + void draw(const sp<const DisplayDevice>& hw); /* * doTransaction - process the transaction. This is a good place to figure @@ -283,7 +299,22 @@ public: // Updates the transform hint in our SurfaceFlingerConsumer to match // the current orientation of the display device. - void updateTransformHint(const sp<const DisplayDevice>& hw) const; + void updateTransformHint(const sp<const DisplayDevice>& hw) ; + + /* ------------------------------------------------------------------------ + * Extensions + */ + virtual bool isExtOnly() const { return false; } + virtual bool isIntOnly() const { return false; } + virtual bool isSecureDisplay() const { return false; } + virtual bool isYuvLayer() const { return false; } + virtual void setPosition(const sp<const DisplayDevice>& /*hw*/, + HWComposer::HWCLayerInterface& /*layer*/, + const State& /*state*/) { } + virtual void setAcquiredFenceIfBlit(int& /*fenceFd */, + HWComposer::HWCLayerInterface& /*layer */) { } + virtual bool canAllowGPUForProtected() const { return false; } + /* * returns the rectangle that crops the content of the layer and scales it @@ -336,6 +367,7 @@ protected: LayerCleaner(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer); }; + Rect reduce(const Rect& win, const Region& exclude) const; private: // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener @@ -419,6 +451,7 @@ private: Vector<BufferItem> mQueueItems; uint64_t mLastFrameNumberReceived; bool mUpdateTexImageFailed; // This is only modified from the main thread + uint32_t mTransformHint; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/LayerBlur.cpp b/services/surfaceflinger/LayerBlur.cpp new file mode 100644 index 0000000..021978d --- /dev/null +++ b/services/surfaceflinger/LayerBlur.cpp @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * 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 + +//#define LOG_NDEBUG 0 + +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> +#include <time.h> + +#include <utils/Errors.h> +#include <utils/Log.h> +#include <utils/Trace.h> +#include <GLES/gl.h> +#include <GLES2/gl2.h> + +#include "LayerBlur.h" +#include "SurfaceFlinger.h" +#include "DisplayDevice.h" +#include "RenderEngine/RenderEngine.h" + +namespace android { +// --------------------------------------------------------------------------- + +// Automatically disables scissor test and restores it when destroyed +class ScopedScissorDisabler { + bool scissorEnabled; +public: + ScopedScissorDisabler(bool enabled) : scissorEnabled(enabled) { + if(scissorEnabled) { + glDisable(GL_SCISSOR_TEST); + } + } + ~ScopedScissorDisabler() { + if(scissorEnabled) { + glEnable(GL_SCISSOR_TEST); + } + }; +}; + +static void setupMeshPartial(Mesh& mesh, Rect rcDraw, Rect rcTexture, int texWidth, int texHeight, int viewportHeight) { + Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); + position[0] = vec2(rcDraw.left, rcDraw.top); + position[1] = vec2(rcDraw.left, rcDraw.bottom); + position[2] = vec2(rcDraw.right, rcDraw.bottom); + position[3] = vec2(rcDraw.right, rcDraw.top); + for(size_t i=0; i<4; ++i) { + position[i].y = viewportHeight - position[i].y; + } + + Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>()); + texCoords[0] = vec2(rcTexture.left/(float)texWidth, 1.0f - rcTexture.top/(float)texHeight); + texCoords[1] = vec2(rcTexture.left/(float)texWidth, 1.0f - rcTexture.bottom/(float)texHeight); + texCoords[2] = vec2(rcTexture.right/(float)texWidth, 1.0f - rcTexture.bottom/(float)texHeight); + texCoords[3] = vec2(rcTexture.right/(float)texWidth, 1.0f - rcTexture.top/(float)texHeight); +} + +static void setupMesh(Mesh& mesh, int width, int height, int viewportHeight) { + Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); + position[0] = vec2(0, 0); + position[1] = vec2(0, height); + position[2] = vec2(width, height); + position[3] = vec2(width, 0); + for(size_t i=0; i<4; ++i) { + position[i].y = viewportHeight - position[i].y; + } + + Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>()); + texCoords[0] = vec2(0, 1.0f); + texCoords[1] = vec2(0, 0); + texCoords[2] = vec2(1.0f, 0); + texCoords[3] = vec2(1.0f, 1.0f); +} + + +LayerBlur::LayerBlur(SurfaceFlinger* flinger, const sp<Client>& client, + const String8& name, uint32_t w, uint32_t h, uint32_t flags) + : Layer(flinger, client, name, w, h, flags), mBlurMaskSampling(1), mBlurMaskAlphaThreshold(0.0f) + ,mLastFrameSequence(0) +{ +#ifdef UI_BLUR + mBlurToken = qtiblur::initBlurToken(); +#endif + + GLuint texnames[3]; + mFlinger->getRenderEngine().genTextures(3, texnames); + mTextureCapture.init(Texture::TEXTURE_2D, texnames[0]); + mTextureBlur.init(Texture::TEXTURE_2D, texnames[1]); + mTextureMasking.init(Texture::TEXTURE_2D, texnames[2]); +} + +LayerBlur::~LayerBlur() { +#ifdef UI_BLUR + qtiblur::releaseBlurToken(mBlurToken); +#endif + + releaseFbo(mFboCapture); + releaseFbo(mFboMasking); + mFlinger->deleteTextureAsync(mTextureCapture.getTextureName()); + mFlinger->deleteTextureAsync(mTextureBlur.getTextureName()); + mFlinger->deleteTextureAsync(mTextureMasking.getTextureName()); +} + +void LayerBlur::onDraw(const sp<const DisplayDevice>& hw, const Region& /*clip*/, + bool useIdentityTransform) +{ + clock_t t1 = clock(); + const ScopedTrace traceTotal(ATRACE_TAG, "Blur.onDraw"); + + const Layer::State& s(getDrawingState()); + + if (s.alpha==0) { + return; + } + + ///// + // NOTE: + // + // Scissor test has been turned on by SurfaceFlinger for NON-primary display + // We need to turn off the scissor test during our fbo drawing + GLboolean isScissorEnabled = false; + glGetBooleanv(GL_SCISSOR_TEST, &isScissorEnabled); + ScopedScissorDisabler _(isScissorEnabled); + // + ///// + + + int hwWidth = hw->getWidth(); + int hwHeight = hw->getHeight(); + + RenderEngine& engine(mFlinger->getRenderEngine()); + + bool savedProjectionYSwap = engine.getProjectionYSwap(); + Rect savedProjectionSourceCrop = engine.getProjectionSourceCrop(); + Transform::orientation_flags savedProjectionRotation = engine.getProjectionRotation(); + size_t savedViewportWidth = engine.getViewportWidth(); + size_t savedViewportHeight = engine.getViewportHeight(); + + + if (mLastFrameSequence != mFlinger->mActiveFrameSequence || + mTextureBlur.getWidth() == 0 || mTextureBlur.getHeight() == 0) { + // full drawing needed. + + + // capture + if (!captureScreen(hw, mFboCapture, mTextureCapture, hwWidth, hwHeight)) { + return; + } + + // blur + size_t outTexWidth = mTextureBlur.getWidth(); + size_t outTexHeight = mTextureBlur.getHeight(); +#ifdef UI_BLUR + if (!qtiblur::blur(mBlurToken, + s.blur, + mTextureCapture.getTextureName(), + mTextureCapture.getWidth(), + mTextureCapture.getHeight(), + mTextureBlur.getTextureName(), + &outTexWidth, + &outTexHeight)) { + return; + } +#endif + + // mTextureBlur now has "Blurred image" + mTextureBlur.setDimensions(outTexWidth, outTexHeight); + + } else { + // We can just re-use mTextureBlur. + // SurfaceFlinger or other LayerBlur object called my draw() multiple times + // while making one frame. + // + // Fall through + } + + // masking + bool masking = false; + sp<Layer> maskLayer = mBlurMaskLayer.promote(); + if (maskLayer != 0) { + // The larger sampling, the faster drawing. + // The smaller sampling, the prettier out line. + int sampling = mBlurMaskSampling >= 1 ? mBlurMaskSampling : 1; + //ALOGV("maskLayer available, sampling:%d", sampling); + masking = drawMaskLayer(maskLayer, hw, mFboMasking, hwWidth, hwHeight, sampling, mTextureMasking); + } + + + // final draw + doDrawFinal(hw, + savedViewportWidth, savedViewportHeight, + savedProjectionSourceCrop, + savedProjectionYSwap, + savedProjectionRotation, + useIdentityTransform, + masking ? &mTextureMasking : 0 + ); + + mLastFrameSequence = mFlinger->mActiveFrameSequence; + + clock_t t2 = clock(); + ALOGV("onDraw took %d ms", (int)(1000*(t2-t1)/CLOCKS_PER_SEC)); +} + + +bool LayerBlur::captureScreen(const sp<const DisplayDevice>& hw, FBO& fbo, Texture& texture, int width, int height) { + ATRACE_CALL(); + ensureFbo(fbo, width, height, texture.getTextureName()); + Transform::orientation_flags rotation = Transform::ROT_0; + if(fbo.fbo == 0) { + ALOGE("captureScreen(). fbo.fbo == 0"); + return false; + } + + GLint savedFramebuffer = 0; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &savedFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)fbo.fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + texture.getTextureTarget(), + texture.getTextureName(), 0); + + mFlinger->getRenderEngine().clearWithColor(0.0f, 0.0f, 0.0f, 1.0f); + if (hw->isPanelInverseMounted()) + rotation = Transform::ROT_180; + mFlinger->renderScreenImplLocked( + hw, + Rect(0,0,width,height), + width, height, + 0, getDrawingState().z-1, + false, + false, + rotation); + + glBindFramebuffer(GL_FRAMEBUFFER, savedFramebuffer); + + texture.setDimensions(width, height); + + return true; +} + +bool LayerBlur::drawMaskLayer(sp<Layer>& maskLayer, const sp<const DisplayDevice>& hw, + FBO& fbo, int width, int height, int sampling, Texture& texture) { + // Draw maskLayer into fbo + ATRACE_CALL(); + + int maskWidth = width/sampling; + int maskHeight = height/sampling; + + ensureFbo(fbo, maskWidth, maskHeight, texture.getTextureName()); + if(fbo.fbo == 0) { + ALOGE("drawMaskLayer(). fbo.fbo == 0"); + return false; + } + + GLint savedFramebuffer = 0; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &savedFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)fbo.fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + texture.getTextureTarget(), + texture.getTextureName(), 0); + + mFlinger->getRenderEngine().setViewportAndProjection( + maskWidth, maskHeight, + Rect(0,0,width,height), + height, + false, + Transform::ROT_0 + ); + setupMesh(mMesh, width, height, height); + mFlinger->getRenderEngine().clearWithColor(0.0f, 0.0f, 0.0f, 0.0f); // alpha must be ZERO + maskLayer->draw(hw); + glBindFramebuffer(GL_FRAMEBUFFER, savedFramebuffer); + + texture.setDimensions(maskWidth, maskHeight); + + return true; +} + +/* + * draw final texture into outer framebuffer + */ +void LayerBlur::doDrawFinal(const sp<const DisplayDevice>& hw, + int savedViewportWidth, int savedViewportHeight, + Rect savedProjectionSourceCrop, + bool savedProjectionYSwap, + Transform::orientation_flags savedRotation, + bool useIdentityTransform, + Texture* maskTexture + ) { + ATRACE_CALL(); + + int hwWidth = hw->getWidth(); + int hwHeight = hw->getHeight(); + + RenderEngine& engine(mFlinger->getRenderEngine()); + const Layer::State& s(getDrawingState()); + + Transform trToDraw(useIdentityTransform ? hw->getTransform() : hw->getTransform() * s.transform); + Transform trToMapTexture(hw->getTransform() * s.transform); + + Rect frameToDraw(trToDraw.transform(Rect(s.active.w, s.active.h))); + Rect frameToMapTexture(trToMapTexture.transform(Rect(s.active.w, s.active.h))); + + engine.setViewportAndProjection( + savedViewportWidth, savedViewportHeight, + savedProjectionSourceCrop, + hwHeight, + savedProjectionYSwap, + savedRotation + ); + + + const mat4 identity; + float textureMatrix[16]; + memcpy(textureMatrix, identity.asArray(), sizeof(textureMatrix)); + + //mTextureBlur.setDimensions(hwWidth, hwHeight); + mTextureBlur.setFiltering(true); + mTextureBlur.setMatrix(textureMatrix); + + if (maskTexture != 0) { + maskTexture->setFiltering(false); + maskTexture->setMatrix(textureMatrix); + } + + setupMeshPartial(mMesh, frameToDraw, frameToMapTexture, hwWidth, hwHeight, + savedProjectionSourceCrop.height()); + + engine.setupLayerTexturing(mTextureBlur); + engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), s.alpha); + if (maskTexture) { + engine.setupLayerMasking(*maskTexture, mBlurMaskAlphaThreshold); + } + engine.drawMesh(mMesh); + engine.disableLayerMasking(); + engine.disableBlending(); + engine.disableTexturing(); + +} + +bool LayerBlur::isVisible() const { + const Layer::State& s(getDrawingState()); + return !(s.flags & layer_state_t::eLayerHidden) && s.alpha; +} + +bool LayerBlur::setBlurMaskLayer(sp<Layer>& maskLayer) { + if (maskLayer == mBlurMaskLayer) { + return false; + } + mBlurMaskLayer = maskLayer; + return true; +} + + +void LayerBlur::initFbo(FBO& fbobj, int width, int height, int textureName) { + GLuint fbo=0; + + glGenFramebuffers(1, &fbo); + glBindTexture(GL_TEXTURE_2D, textureName); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, + 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + GLint savedFramebuffer = 0; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &savedFramebuffer); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, textureName, 0); + glBindFramebuffer(GL_FRAMEBUFFER, savedFramebuffer); + + fbobj.fbo = fbo; + fbobj.width = width; + fbobj.height = height; +} + +void LayerBlur::releaseFbo(FBO& fbo) { + if(fbo.fbo != 0) { + glDeleteFramebuffers(1, (GLuint*)&fbo.fbo); + } + fbo.fbo = 0; + fbo.width = 0; + fbo.height = 0; +} + +void LayerBlur::ensureFbo(FBO& fbo, int width, int height, int textureName) { + if(fbo.fbo != 0) { + if(fbo.width != width || fbo.height != height) { + releaseFbo(fbo); + } + } + if(fbo.fbo == 0) { + initFbo(fbo, width, height, textureName); + } +} + + +// --------------------------------------------------------------------------- + +}; // namespace android diff --git a/services/surfaceflinger/LayerBlur.h b/services/surfaceflinger/LayerBlur.h new file mode 100644 index 0000000..251423e --- /dev/null +++ b/services/surfaceflinger/LayerBlur.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Not a Contribution. + * + * 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. + */ + +#ifndef ANDROID_LAYER_BLUR_H +#define ANDROID_LAYER_BLUR_H + +#include <stdint.h> +#include <sys/types.h> + +#include "Layer.h" + +#ifdef UI_BLUR +#include "Blur.h" // libuiblur.so +#endif + +// --------------------------------------------------------------------------- + +namespace android { + +/** + * Blur layer object. + * Actual blurring logics are capsulated in libuiblur.so + */ +class LayerBlur : public Layer +{ +public: + LayerBlur(SurfaceFlinger* flinger, const sp<Client>& client, + const String8& name, uint32_t w, uint32_t h, uint32_t flags); + virtual ~LayerBlur(); + + virtual const char* getTypeId() const { return "LayerBlur"; } + virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip, + bool useIdentityTransform); + virtual bool isOpaque(const Layer::State& /*s*/) const { return false; } + virtual bool isSecure() const { return false; } + virtual bool isFixedSize() const { return true; } + virtual bool isVisible() const; + + virtual bool isBlurLayer() const { return true; } + virtual bool setBlurMaskLayer(sp<Layer>& maskLayer); + virtual bool setBlurMaskSampling(int32_t sampling) { mBlurMaskSampling = sampling; return true; } + virtual bool setBlurMaskAlphaThreshold(float alpha) { mBlurMaskAlphaThreshold = alpha; return true; } + +private: +#ifdef UI_BLUR + qtiblur::BLUR_TOKEN mBlurToken; +#endif + wp<Layer> mBlurMaskLayer; + int32_t mBlurMaskSampling; + float mBlurMaskAlphaThreshold; + uint32_t mLastFrameSequence; + + class FBO { + public: + FBO() : fbo(0), width(0), height(0) {} + int fbo; + int width; + int height; + }; + + void initFbo(FBO& fbo, int width, int height, int textureName); + void releaseFbo(FBO& fbo); + void ensureFbo(FBO& fbo, int width, int height, int textureName); + + + FBO mFboCapture; + Texture mTextureCapture; + + Texture mTextureBlur; + + FBO mFboMasking; + Texture mTextureMasking; + + bool captureScreen(const sp<const DisplayDevice>& hw, + FBO& fbo, Texture& texture, int width, int height); + void doDrawFinal(const sp<const DisplayDevice>& hw, + int savedViewportWidth, int savedViewportHeight, + Rect savedProjectionSourceCrop, bool savedProjectionYSwap, + Transform::orientation_flags savedRotation, bool useIdentityTransform, + Texture* maskTexture); + bool drawMaskLayer(sp<Layer>& maskLayer, const sp<const DisplayDevice>& hw, + FBO& fbo, int width, int height, int sampling, Texture& texture); + +}; + +// --------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_LAYER_BLUR_H diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp index 14aa328..5afd291 100644 --- a/services/surfaceflinger/LayerDim.cpp +++ b/services/surfaceflinger/LayerDim.cpp @@ -40,7 +40,7 @@ LayerDim::~LayerDim() { } void LayerDim::onDraw(const sp<const DisplayDevice>& hw, - const Region& /* clip */, bool useIdentityTransform) const + const Region& /* clip */, bool useIdentityTransform) { const State& s(getDrawingState()); if (s.alpha>0) { @@ -58,6 +58,15 @@ bool LayerDim::isVisible() const { return !(s.flags & layer_state_t::eLayerHidden) && s.alpha; } +void LayerDim::setPerFrameData(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer) { + HWComposer& hwc = mFlinger->getHwComposer(); + + Layer::setPerFrameData(hw, layer); + if (hwc.hasDimComposition()) { + layer.setDim(); + } +} // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h index a0cfca9..01f71cc 100644 --- a/services/surfaceflinger/LayerDim.h +++ b/services/surfaceflinger/LayerDim.h @@ -35,11 +35,13 @@ public: virtual const char* getTypeId() const { return "LayerDim"; } virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip, - bool useIdentityTransform) const; + bool useIdentityTransform); virtual bool isOpaque(const Layer::State&) const { return false; } virtual bool isSecure() const { return false; } virtual bool isFixedSize() const { return true; } virtual bool isVisible() const; + virtual void setPerFrameData(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface& layer); }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp index 0dab872..14607ca 100644 --- a/services/surfaceflinger/RenderEngine/Description.cpp +++ b/services/surfaceflinger/RenderEngine/Description.cpp @@ -33,6 +33,8 @@ Description::Description() : mOpaque = true; mTextureEnabled = false; mColorMatrixEnabled = false; + mMaskTextureEnabled = false; + mMaskAlphaThreshold = 0.0f; memset(mColor, 0, sizeof(mColor)); } @@ -92,5 +94,14 @@ const mat4& Description::getColorMatrix() const { return mColorMatrix; } +void Description::setMasking(const Texture& maskTexture, float alphaThreshold) { + mMaskTexture = maskTexture; + mMaskTextureEnabled = true; + mMaskAlphaThreshold = alphaThreshold; +} + +void Description::disableMasking() { + mMaskTextureEnabled = false; +} } /* namespace android */ diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h index 8a3447c..2bfb632 100644 --- a/services/surfaceflinger/RenderEngine/Description.h +++ b/services/surfaceflinger/RenderEngine/Description.h @@ -53,6 +53,9 @@ class Description { bool mColorMatrixEnabled; mat4 mColorMatrix; + Texture mMaskTexture; + bool mMaskTextureEnabled; + GLclampf mMaskAlphaThreshold; public: Description(); @@ -67,6 +70,8 @@ public: void setProjectionMatrix(const mat4& mtx); void setColorMatrix(const mat4& mtx); const mat4& getColorMatrix() const; + void setMasking(const Texture& maskTexture, float alphaThreshold); + void disableMasking(); private: bool mUniformsDirty; diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp index 1a9f59b..853a4eb 100644 --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp @@ -92,14 +92,29 @@ void GLES11RenderEngine::setViewportAndProjection( case Transform::ROT_0: break; case Transform::ROT_90: - glRotatef(90, 0, 0, 1); + { + float x1 = (l+r)/2; + float y1 = (t+b)/2; + glTranslatef(x1-y1, x1+y1, 0); + glRotatef(270, 0, 0, 1); break; + } case Transform::ROT_180: + { + float x1 = (l+r)/2; + float y1 = (t+b)/2; + glTranslatef(x1*2, y1*2, 0); glRotatef(180, 0, 0, 1); break; + } case Transform::ROT_270: - glRotatef(270, 0, 0, 1); + { + float x1 = (l+r)/2; + float y1 = (t+b)/2; + glTranslatef(x1+y1, y1-x1, 0); + glRotatef(90, 0, 0, 1); break; + } default: break; } @@ -210,28 +225,46 @@ void GLES11RenderEngine::disableBlending() { } void GLES11RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, - uint32_t* texName, uint32_t* fbName, uint32_t* status) { + uint32_t* texName, uint32_t* fbName, uint32_t* status, + bool useReadPixels, int reqWidth, int reqHeight) { GLuint tname, name; - // turn our EGLImage into a texture - glGenTextures(1, &tname); - glBindTexture(GL_TEXTURE_2D, tname); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); - - // create a Framebuffer Object to render into - glGenFramebuffersOES(1, &name); - glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); - glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, - GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); + if (!useReadPixels) { + // turn our EGLImage into a texture + glGenTextures(1, &tname); + glBindTexture(GL_TEXTURE_2D, tname); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); + + // create a Framebuffer Object to render into + glGenFramebuffersOES(1, &name); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); + glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, + GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); + } else { + // since we're going to use glReadPixels() anyways, + // use an intermediate renderbuffer instead + glGenRenderbuffersOES(1, &tname); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); + glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, reqWidth, reqHeight); + // create a FBO to render into + glGenFramebuffersOES(1, &name); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, + GL_RENDERBUFFER_OES, tname); + } *status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); *texName = tname; *fbName = name; } -void GLES11RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName) { +void GLES11RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName, + bool useReadPixels) { glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); glDeleteFramebuffersOES(1, &fbName); - glDeleteTextures(1, &texName); + if (!useReadPixels) + glDeleteTextures(1, &texName); + else + glDeleteRenderbuffersOES(1, &texName); } void GLES11RenderEngine::setupFillWithColor(float r, float g, float b, float a) { diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h index 08de646..cb13ee0 100644 --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h @@ -40,8 +40,9 @@ class GLES11RenderEngine : public RenderEngine { GLint mMaxTextureSize; virtual void bindImageAsFramebuffer(EGLImageKHR image, - uint32_t* texName, uint32_t* fbName, uint32_t* status); - virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName); + uint32_t* texName, uint32_t* fbName, uint32_t* status, bool useReadPixels, + int reqWidth, int reqHeight); + virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName, bool useReadPixels); public: GLES11RenderEngine(); @@ -59,6 +60,8 @@ protected: virtual void setupFillWithColor(float r, float g, float b, float a) ; virtual void disableTexturing(); virtual void disableBlending(); + virtual void setupLayerMasking(const Texture& /*maskTexture*/, float /*alphaThreshold*/) {} + virtual void disableLayerMasking() {} virtual void drawMesh(const Mesh& mesh); diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp index 1fabaf5..6333a41 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp @@ -40,7 +40,7 @@ namespace android { // --------------------------------------------------------------------------- GLES20RenderEngine::GLES20RenderEngine() : - mVpWidth(0), mVpHeight(0) { + mVpWidth(0), mVpHeight(0), mProjectionRotation(Transform::ROT_0) { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); @@ -115,6 +115,9 @@ void GLES20RenderEngine::setViewportAndProjection( mState.setProjectionMatrix(m); mVpWidth = vpw; mVpHeight = vph; + mProjectionSourceCrop = sourceCrop; + mProjectionYSwap = yswap; + mProjectionRotation = rotation; } void GLES20RenderEngine::setupLayerBlending( @@ -185,27 +188,44 @@ void GLES20RenderEngine::disableBlending() { void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, - uint32_t* texName, uint32_t* fbName, uint32_t* status) { + uint32_t* texName, uint32_t* fbName, uint32_t* status, + bool useReadPixels, int reqWidth, int reqHeight) { GLuint tname, name; - // turn our EGLImage into a texture - glGenTextures(1, &tname); - glBindTexture(GL_TEXTURE_2D, tname); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); - - // create a Framebuffer Object to render into - glGenFramebuffers(1, &name); - glBindFramebuffer(GL_FRAMEBUFFER, name); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); + if (!useReadPixels) { + // turn our EGLImage into a texture + glGenTextures(1, &tname); + glBindTexture(GL_TEXTURE_2D, tname); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); + + // create a Framebuffer Object to render into + glGenFramebuffers(1, &name); + glBindFramebuffer(GL_FRAMEBUFFER, name); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); + } else { + // since we're going to use glReadPixels() anyways, + // use an intermediate renderbuffer instead + glGenRenderbuffers(1, &tname); + glBindRenderbuffer(GL_RENDERBUFFER, tname); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, reqWidth, reqHeight); + // create a FBO to render into + glGenFramebuffers(1, &name); + glBindFramebuffer(GL_FRAMEBUFFER, name); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, tname); + } *status = glCheckFramebufferStatus(GL_FRAMEBUFFER); *texName = tname; *fbName = name; } -void GLES20RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName) { +void GLES20RenderEngine::unbindFramebuffer(uint32_t texName, uint32_t fbName, + bool useReadPixels) { glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &fbName); - glDeleteTextures(1, &texName); + if (!useReadPixels) + glDeleteTextures(1, &texName); + else + glDeleteRenderbuffers(1, &texName); } void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) { @@ -247,6 +267,30 @@ void GLES20RenderEngine::dump(String8& result) { RenderEngine::dump(result); } +void GLES20RenderEngine::setupLayerMasking(const Texture& maskTexture, float alphaThreshold) { + glActiveTexture(GL_TEXTURE0 + 1); + GLuint target = maskTexture.getTextureTarget(); + glBindTexture(target, maskTexture.getTextureName()); + GLenum filter = GL_NEAREST; + if (maskTexture.getFiltering()) { + filter = GL_LINEAR; + } + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter); + + if (alphaThreshold < 0) alphaThreshold = 0; + if (alphaThreshold > 1.0f) alphaThreshold = 1.0f; + + mState.setMasking(maskTexture, alphaThreshold); + glActiveTexture(GL_TEXTURE0); +} + +void GLES20RenderEngine::disableLayerMasking() { + mState.disableMasking(); +} + // --------------------------------------------------------------------------- }; // namespace android // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h index 819356a..414a999 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h @@ -42,6 +42,9 @@ class GLES20RenderEngine : public RenderEngine { GLint mMaxTextureSize; GLuint mVpWidth; GLuint mVpHeight; + Rect mProjectionSourceCrop; + bool mProjectionYSwap; + Transform::orientation_flags mProjectionRotation; struct Group { GLuint texture; @@ -55,8 +58,9 @@ class GLES20RenderEngine : public RenderEngine { Vector<Group> mGroupStack; virtual void bindImageAsFramebuffer(EGLImageKHR image, - uint32_t* texName, uint32_t* fbName, uint32_t* status); - virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName); + uint32_t* texName, uint32_t* fbName, uint32_t* status, + bool useReadPixels, int reqWidth, int reqHeight); + virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName, bool useReadPixels); public: GLES20RenderEngine(); @@ -75,11 +79,18 @@ protected: virtual mat4 setupColorTransform(const mat4& colorTransform); virtual void disableTexturing(); virtual void disableBlending(); + virtual void setupLayerMasking(const Texture& maskTexture, float alphaThreshold); + virtual void disableLayerMasking(); virtual void drawMesh(const Mesh& mesh); virtual size_t getMaxTextureSize() const; virtual size_t getMaxViewportDims() const; + virtual bool getProjectionYSwap() { return mProjectionYSwap; } + virtual size_t getViewportWidth() const { return mVpWidth; } + virtual size_t getViewportHeight() const { return mVpHeight; } + virtual Rect getProjectionSourceCrop() const { return mProjectionSourceCrop; } + virtual Transform::orientation_flags getProjectionRotation() const { return mProjectionRotation; } }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp index 0424e0c..936cb1b 100644 --- a/services/surfaceflinger/RenderEngine/Program.cpp +++ b/services/surfaceflinger/RenderEngine/Program.cpp @@ -64,6 +64,8 @@ Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const c mSamplerLoc = glGetUniformLocation(programId, "sampler"); mColorLoc = glGetUniformLocation(programId, "color"); mAlphaPlaneLoc = glGetUniformLocation(programId, "alphaPlane"); + mSamplerMaskLoc = glGetUniformLocation(programId, "samplerMask"); + mMaskAlphaThresholdLoc = glGetUniformLocation(programId, "maskAlphaThreshold"); // set-up the default values for our uniforms glUseProgram(programId); @@ -143,6 +145,12 @@ void Program::setUniforms(const Description& desc) { } // these uniforms are always present glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.mProjectionMatrix.asArray()); + if (mSamplerMaskLoc >= 0) { + glUniform1i(mSamplerMaskLoc, 1); + } + if (mMaskAlphaThresholdLoc >= 0) { + glUniform1f(mMaskAlphaThresholdLoc, desc.mMaskAlphaThreshold); + } } } /* namespace android */ diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/Program.h index 36bd120..08dee59 100644 --- a/services/surfaceflinger/RenderEngine/Program.h +++ b/services/surfaceflinger/RenderEngine/Program.h @@ -84,6 +84,9 @@ private: /* location of the color uniform */ GLint mColorLoc; + + GLint mSamplerMaskLoc; + GLint mMaskAlphaThresholdLoc; }; diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp index ba11259..33ff7d0 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp +++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 + #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> @@ -110,9 +112,27 @@ void ProgramCache::primeCache() { shaderCount++; } } + + // Keys that are actually used by blurring. + // This is obtained by log msg from useProgram() + uint32_t blurringKeys[] = { + 0x01000015, + 0x01000011, + }; + for (size_t i=0; i<sizeof(blurringKeys)/sizeof(blurringKeys[0]); ++i) { + Key shaderKey; + shaderKey.set(blurringKeys[i], blurringKeys[i]); + Program* program = mCache.valueFor(shaderKey); + if (program == NULL) { + program = generateProgram(shaderKey); + mCache.add(shaderKey, program); + shaderCount++; + } + } + nsecs_t timeAfter = systemTime(); float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6; - ALOGD("shader cache generated - %u shaders in %f ms\n", shaderCount, compileTimeMs); + ALOGD("SF. shader cache generated - %u shaders in %f ms\n", shaderCount, compileTimeMs); } ProgramCache::Key ProgramCache::computeKey(const Description& description) { @@ -129,15 +149,20 @@ ProgramCache::Key ProgramCache::computeKey(const Description& description) { .set(Key::OPACITY_MASK, description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT) .set(Key::COLOR_MATRIX_MASK, - description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF); + description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF) + .set(Key::TEXTURE_MASKING_MASK, + !description.mMaskTextureEnabled ? Key::TEXTURE_MASKING_OFF : + description.mMaskTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES ? Key::TEXTURE_MASKING_EXT : + description.mMaskTexture.getTextureTarget() == GL_TEXTURE_2D ? Key::TEXTURE_MASKING_2D : + Key::TEXTURE_MASKING_OFF); return needs; } String8 ProgramCache::generateVertexShader(const Key& needs) { Formatter vs; if (needs.isTexturing()) { - vs << "attribute vec4 texCoords;" - << "varying vec2 outTexCoords;"; + vs << "attribute vec4 texCoords;" + << "varying vec2 outTexCoords;"; } vs << "attribute vec4 position;" << "uniform mat4 projection;" @@ -145,7 +170,7 @@ String8 ProgramCache::generateVertexShader(const Key& needs) { << "void main(void) {" << indent << "gl_Position = projection * position;"; if (needs.isTexturing()) { - vs << "outTexCoords = (texture * texCoords).st;"; + vs << "outTexCoords = (texture * texCoords).st;"; } vs << dedent << "}"; return vs.getString(); @@ -169,6 +194,14 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) { fs << "uniform vec4 color;"; } + if (needs.getTextureMaskingTarget() == Key::TEXTURE_MASKING_EXT) { + fs << "uniform samplerExternalOES samplerMask;"; + } else if (needs.getTextureMaskingTarget() == Key::TEXTURE_MASKING_2D) { + fs << "uniform sampler2D samplerMask;"; + } + if (needs.getTextureMaskingTarget() != Key::TEXTURE_MASKING_OFF) { + fs << "uniform float maskAlphaThreshold;"; + } if (needs.hasPlaneAlpha()) { fs << "uniform float alphaPlane;"; } @@ -177,7 +210,12 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { } fs << "void main(void) {" << indent; if (needs.isTexturing()) { - fs << "gl_FragColor = texture2D(sampler, outTexCoords);"; + if (needs.getTextureMaskingTarget() != Key::TEXTURE_MASKING_OFF) { + fs << "if (texture2D(samplerMask, outTexCoords).a <= maskAlphaThreshold) discard;" + << "gl_FragColor = texture2D(sampler, outTexCoords);"; + } else { + fs << "gl_FragColor = texture2D(sampler, outTexCoords);"; + } } else { fs << "gl_FragColor = color;"; } @@ -235,9 +273,6 @@ void ProgramCache::useProgram(const Description& description) { program = generateProgram(needs); mCache.add(needs, program); time += systemTime(); - - //ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)", - // needs.mNeeds, uint32_t(ns2ms(time)), mCache.size()); } // here we have a suitable program for this description diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h index 1fa53d3..3824e73 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.h +++ b/services/surfaceflinger/RenderEngine/ProgramCache.h @@ -69,6 +69,11 @@ public: COLOR_MATRIX_OFF = 0x00000000, COLOR_MATRIX_ON = 0x00000020, COLOR_MATRIX_MASK = 0x00000020, + + TEXTURE_MASKING_OFF = 0x00000000, + TEXTURE_MASKING_EXT = 0x00800000, + TEXTURE_MASKING_2D = 0x01000000, + TEXTURE_MASKING_MASK = 0x01800000, }; inline Key() : mKey(0) { } @@ -97,6 +102,12 @@ public: inline bool hasColorMatrix() const { return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON; } + inline bool isTextureMasking() const { + return (mKey & TEXTURE_MASKING_MASK) != TEXTURE_MASKING_OFF; + } + inline int getTextureMaskingTarget() const { + return (mKey & TEXTURE_MASKING_MASK); + } // this is the definition of a friend function -- not a method of class Needs friend inline int strictly_order_type(const Key& lhs, const Key& rhs) { diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index 7cd42e4..cb1d14c 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -83,7 +83,6 @@ RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) { EGL_CONTEXT_CLIENT_VERSION, contextClientVersion, // MUST be first #ifdef EGL_IMG_context_priority #ifdef HAS_CONTEXT_PRIORITY -#warning "using EGL_IMG_context_priority" EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, #endif #endif @@ -262,9 +261,11 @@ void RenderEngine::dump(String8& result) { // --------------------------------------------------------------------------- RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer( - RenderEngine& engine, EGLImageKHR image) : mEngine(engine) + RenderEngine& engine, EGLImageKHR image, bool useReadPixels, + int reqWidth, int reqHeight) : mEngine(engine), mUseReadPixels(useReadPixels) { - mEngine.bindImageAsFramebuffer(image, &mTexName, &mFbName, &mStatus); + mEngine.bindImageAsFramebuffer(image, &mTexName, &mFbName, &mStatus, + useReadPixels, reqWidth, reqHeight); ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d", mStatus); @@ -272,7 +273,7 @@ RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer( RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() { // back to main framebuffer - mEngine.unbindFramebuffer(mTexName, mFbName); + mEngine.unbindFramebuffer(mTexName, mFbName, mUseReadPixels); } status_t RenderEngine::BindImageAsFramebuffer::getStatus() const { diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index 31a961e..a669fdd 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -51,8 +51,11 @@ class RenderEngine { EGLContext mEGLContext; void setEGLHandles(EGLConfig config, EGLContext ctxt); - virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status) = 0; - virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName) = 0; + virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, + uint32_t* fbName, uint32_t* status, bool useReadPixels, int reqWidth, + int reqHeight) = 0; + virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName, + bool useReadPixels) = 0; protected: RenderEngine(); @@ -83,8 +86,10 @@ public: RenderEngine& mEngine; uint32_t mTexName, mFbName; uint32_t mStatus; + bool mUseReadPixels; public: - BindImageAsFramebuffer(RenderEngine& engine, EGLImageKHR image); + BindImageAsFramebuffer(RenderEngine& engine, EGLImageKHR image, + bool useReadPixels, int reqWidth, int reqHeight); ~BindImageAsFramebuffer(); int getStatus() const; }; @@ -105,6 +110,8 @@ public: virtual void disableTexturing() = 0; virtual void disableBlending() = 0; + virtual void setupLayerMasking(const Texture& maskTexture, float alphaThreshold) = 0; + virtual void disableLayerMasking() = 0; // drawing virtual void drawMesh(const Mesh& mesh) = 0; @@ -112,6 +119,11 @@ public: // queries virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; + virtual bool getProjectionYSwap() { return 0; } + virtual size_t getViewportWidth() const { return 1; } + virtual size_t getViewportHeight() const { return 1; } + virtual Rect getProjectionSourceCrop() const { return Rect(0, 0, 1, 1); } + virtual Transform::orientation_flags getProjectionRotation() const { return Transform::ROT_0; } EGLConfig getEGLConfig() const; EGLContext getEGLContext() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index fdc3650..40e5da1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <stdint.h> @@ -27,6 +28,7 @@ #include <EGL/egl.h> #include <cutils/log.h> +#include <cutils/iosched_policy.h> #include <cutils/properties.h> #include <binder/IPCThreadState.h> @@ -67,6 +69,7 @@ #include "EventThread.h" #include "Layer.h" #include "LayerDim.h" +#include "LayerBlur.h" #include "SurfaceFlinger.h" #include "DisplayHardware/FramebufferSurface.h" @@ -77,6 +80,7 @@ #include "RenderEngine/RenderEngine.h" #include <cutils/compiler.h> +#include "DisplayUtils.h" #define DISPLAY_COUNT 1 @@ -122,6 +126,8 @@ const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER" const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); const String16 sDump("android.permission.DUMP"); +static sp<Layer> lastSurfaceViewLayer; + // --------------------------------------------------------------------------- SurfaceFlinger::SurfaceFlinger() @@ -150,10 +156,12 @@ SurfaceFlinger::SurfaceFlinger() mHWVsyncAvailable(false), mDaltonize(false), mHasColorMatrix(false), + mHasSecondaryColorMatrix(false), mHasPoweredOff(false), mFrameBuckets(), mTotalTime(0), - mLastSwapTime(0) + mLastSwapTime(0), + mActiveFrameSequence(0) { ALOGI("SurfaceFlinger is starting"); @@ -446,17 +454,24 @@ void SurfaceFlinger::init() { eglInitialize(mEGLDisplay, NULL, NULL); // start the EventThread - sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, - vsyncPhaseOffsetNs, true, "app"); - mEventThread = new EventThread(vsyncSrc); - sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, - sfVsyncPhaseOffsetNs, true, "sf"); - mSFEventThread = new EventThread(sfVsyncSrc); - mEventQueue.setEventThread(mSFEventThread); + if (vsyncPhaseOffsetNs != sfVsyncPhaseOffsetNs) { + sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, + vsyncPhaseOffsetNs, true, "app"); + mEventThread = new EventThread(vsyncSrc); + sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, + sfVsyncPhaseOffsetNs, true, "sf"); + mSFEventThread = new EventThread(sfVsyncSrc); + mEventQueue.setEventThread(mSFEventThread); + } else { + sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, + vsyncPhaseOffsetNs, true, "sf-app"); + mEventThread = new EventThread(vsyncSrc); + mEventQueue.setEventThread(mEventThread); + } // Initialize the H/W composer object. There may or may not be an // actual hardware composer underneath. - mHwc = new HWComposer(this, + mHwc = DisplayUtils::getInstance()->getHWCInstance(this, *static_cast<HWComposer::EventHandler *>(this)); // get a RenderEngine for the given display / config (can't fail) @@ -497,6 +512,13 @@ void SurfaceFlinger::init() { ALOGD("marking display %zu as acquired/unblanked", i); hw->setPowerMode(HWC_POWER_MODE_NORMAL); } + // When a non-virtual display device is added at boot time, + // update the active config by querying HWC otherwise the + // default config (config 0) will be used. + int activeConfig = mHwc->getActiveConfig(hwcId); + if (activeConfig >= 0) { + hw->setActiveConfig(activeConfig); + } mDisplays.add(token, hw); } } @@ -507,6 +529,7 @@ void SurfaceFlinger::init() { mEventControlThread = new EventControlThread(this); mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); + android_set_rt_ioprio(mEventControlThread->getTid(), 1); // set a fake vsync period if there is no HWComposer if (mHwc->initCheck() != NO_ERROR) { @@ -626,10 +649,21 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display, info.orientation = 0; } - info.w = hwConfig.width; - info.h = hwConfig.height; - info.xdpi = xdpi; - info.ydpi = ydpi; + char value[PROPERTY_VALUE_MAX]; + property_get("ro.sf.hwrotation", value, "0"); + int additionalRot = atoi(value) / 90; + if ((type == DisplayDevice::DISPLAY_PRIMARY) && (additionalRot & DisplayState::eOrientationSwapMask)) { + info.h = hwConfig.width; + info.w = hwConfig.height; + info.xdpi = ydpi; + info.ydpi = xdpi; + } + else { + 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; info.colorTransform = hwConfig.colorTransform; @@ -695,8 +729,10 @@ void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& hw, int mo return; } - hw->setActiveConfig(mode); - getHwComposer().setActiveConfig(type, mode); + status_t status = getHwComposer().setActiveConfig(type, mode); + if (status == NO_ERROR) { + hw->setActiveConfig(mode); + } } status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) { @@ -869,6 +905,7 @@ void SurfaceFlinger::onHotplugReceived(int type, bool connected) { } else { mCurrentState.displays.removeItem(mBuiltinDisplays[type]); mBuiltinDisplays[type].clear(); + updateVisibleRegionsDirty(); } setTransactionFlags(eDisplayTransactionNeeded); @@ -1045,6 +1082,8 @@ void SurfaceFlinger::postComposition() mAnimFrameTracker.advanceFrame(); } + dumpDrawCycle(false); + if (hw->getPowerMode() == HWC_POWER_MODE_OFF) { return; } @@ -1067,6 +1106,7 @@ void SurfaceFlinger::postComposition() } void SurfaceFlinger::rebuildLayerStacks() { + updateExtendedMode(); // rebuild the visible layer list per screen if (CC_UNLIKELY(mVisibleRegionsDirty)) { ATRACE_CALL(); @@ -1082,14 +1122,13 @@ void SurfaceFlinger::rebuildLayerStacks() { const Transform& tr(hw->getTransform()); const Rect bounds(hw->getBounds()); if (hw->isDisplayOn()) { - SurfaceFlinger::computeVisibleRegions(layers, + computeVisibleRegions(hw->getHwcDisplayId(), 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); @@ -1155,7 +1194,7 @@ void SurfaceFlinger::setUpHWComposer() { 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) { + if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix || mHasSecondaryColorMatrix) { cur->setSkip(true); } } @@ -1169,6 +1208,8 @@ void SurfaceFlinger::setUpHWComposer() { sp<const DisplayDevice> hw(mDisplays[dpy]); const int32_t id = hw->getHwcDisplayId(); if (id >= 0) { + bool freezeSurfacePresent = false; + isfreezeSurfacePresent(freezeSurfacePresent, hw, id); const Vector< sp<Layer> >& currentLayers( hw->getVisibleLayersSortedByZ()); const size_t count = currentLayers.size(); @@ -1181,6 +1222,11 @@ void SurfaceFlinger::setUpHWComposer() { */ const sp<Layer>& layer(currentLayers[i]); layer->setPerFrameData(hw, *cur); + setOrientationEventControl(freezeSurfacePresent,id); + if(!strncmp(layer->getName(), "SurfaceView", + 11)) { + lastSurfaceViewLayer = layer; + } } } } @@ -1205,6 +1251,8 @@ void SurfaceFlinger::setUpHWComposer() { } } + dumpDrawCycle(true); + status_t err = hwc.prepare(); ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); @@ -1227,6 +1275,8 @@ void SurfaceFlinger::doComposition() { // repaint the framebuffer (if needed) doDisplayComposition(hw, dirtyRegion); + ++mActiveFrameSequence; + hw->dirtyRegion.clear(); hw->flip(hw->swapRegion); hw->swapRegion.clear(); @@ -1287,6 +1337,7 @@ void SurfaceFlinger::postFramebuffer() if (flipCount % LOG_FRAME_STATS_PERIOD == 0) { logFrameStats(); } + ALOGV_IF(mFrameRateHelper.update(), "FPS: %d", mFrameRateHelper.get()); } void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) @@ -1439,6 +1490,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (state.surface != NULL) { int width = 0; + DisplayUtils* displayUtils = DisplayUtils::getInstance(); int status = state.surface->query( NATIVE_WINDOW_WIDTH, &width); ALOGE_IF(status != NO_ERROR, @@ -1451,15 +1503,21 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (MAX_VIRTUAL_DISPLAY_DIMENSION == 0 || (width <= MAX_VIRTUAL_DISPLAY_DIMENSION && height <= MAX_VIRTUAL_DISPLAY_DIMENSION)) { - hwcDisplayId = allocateHwcDisplayId(state.type); + int usage = 0; + status = state.surface->query( + NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage); + ALOGW_IF(status != NO_ERROR, + "Unable to query usage (%d)", status); + if ( (status == NO_ERROR) && + displayUtils->canAllocateHwcDisplayIdForVDS(usage)) { + hwcDisplayId = allocateHwcDisplayId(state.type); + } } - sp<VirtualDisplaySurface> vds = new VirtualDisplaySurface( - *mHwc, hwcDisplayId, state.surface, - bqProducer, bqConsumer, state.displayName); + displayUtils->initVDSInstance(mHwc, hwcDisplayId, state.surface, + dispSurface, producer, bqProducer, bqConsumer, + state.displayName, state.isSecure, state.type); - dispSurface = vds; - producer = vds; } } else { ALOGE_IF(state.surface!=NULL, @@ -1475,7 +1533,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) } const wp<IBinder>& display(curr.keyAt(i)); - if (dispSurface != NULL) { + if (dispSurface != NULL && producer != NULL) { sp<DisplayDevice> hw = new DisplayDevice(this, state.type, hwcDisplayId, mHwc->getFormat(hwcDisplayId), state.isSecure, @@ -1485,6 +1543,16 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) hw->setProjection(state.orientation, state.viewport, state.frame); hw->setDisplayName(state.displayName); + // When a new display device is added update the active + // config by querying HWC otherwise the default config + // (config 0) will be used. + if (hwcDisplayId >= DisplayDevice::DISPLAY_PRIMARY && + hwcDisplayId < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { + int activeConfig = mHwc->getActiveConfig(hwcDisplayId); + if (activeConfig >= 0) { + hw->setActiveConfig(activeConfig); + } + } mDisplays.add(display, hw); if (state.isVirtualDisplay()) { if (hwcDisplayId >= 0) { @@ -1643,7 +1711,7 @@ void SurfaceFlinger::commitTransaction() mTransactionCV.broadcast(); } -void SurfaceFlinger::computeVisibleRegions( +void SurfaceFlinger::computeVisibleRegions(size_t dpy, const LayerVector& currentLayers, uint32_t layerStack, Region& outDirtyRegion, Region& outOpaqueRegion) { @@ -1654,6 +1722,9 @@ void SurfaceFlinger::computeVisibleRegions( Region dirty; outDirtyRegion.clear(); + bool bIgnoreLayers = false; + int indexLOI = -1; + getIndexLOI(dpy, currentLayers, bIgnoreLayers, indexLOI); size_t i = currentLayers.size(); while (i--) { @@ -1662,8 +1733,9 @@ void SurfaceFlinger::computeVisibleRegions( // 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) + if(updateLayerVisibleNonTransparentRegion(dpy, layer, + bIgnoreLayers, indexLOI, + layerStack, i)) continue; /* @@ -1887,11 +1959,14 @@ void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw, } } - if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) { + if (CC_LIKELY(!mDaltonize && !mHasColorMatrix && !mHasSecondaryColorMatrix)) { if (!doComposeSurfaces(hw, dirtyRegion)) return; } else { RenderEngine& engine(getRenderEngine()); mat4 colorMatrix = mColorMatrix; + if (mHasSecondaryColorMatrix) { + colorMatrix = mHasColorMatrix ? (colorMatrix * mSecondaryColorMatrix) : mSecondaryColorMatrix; + } if (mDaltonize) { colorMatrix = colorMatrix * mDaltonizer(); } @@ -1954,7 +2029,7 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const // screen is already cleared here if (!region.isEmpty()) { // can happen with SurfaceView - drawWormhole(hw, region); + drawWormHoleIfRequired(cur, end, hw, region); } } @@ -2096,6 +2171,8 @@ void SurfaceFlinger::setTransactionState( uint32_t flags) { ATRACE_CALL(); + + delayDPTransactionIfNeeded(displays); Mutex::Autolock _l(mStateLock); uint32_t transactionFlags = 0; @@ -2241,6 +2318,41 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTransactionNeeded|eTraversalNeeded; } } + if (what & layer_state_t::eBlurChanged) { + ALOGV("eBlurChanged"); + if (layer->setBlur(uint8_t(255.0f*s.blur+0.5f))) { + flags |= eTraversalNeeded; + } + } + if (what & layer_state_t::eBlurMaskSurfaceChanged) { + ALOGV("eBlurMaskSurfaceChanged"); + sp<Layer> maskLayer = 0; + if (s.blurMaskSurface != 0) { + maskLayer = client->getLayerUser(s.blurMaskSurface); + } + if (maskLayer == 0) { + ALOGV("eBlurMaskSurfaceChanged. maskLayer == 0"); + } else { + ALOGV("eBlurMaskSurfaceChagned. maskLayer.z == %d", maskLayer->getCurrentState().z); + if (maskLayer->isBlurLayer()) { + ALOGE("Blur layer can not be used as blur mask surface"); + maskLayer = 0; + } + } + if (layer->setBlurMaskLayer(maskLayer)) { + flags |= eTraversalNeeded; + } + } + if (what & layer_state_t::eBlurMaskSamplingChanged) { + if (layer->setBlurMaskSampling(s.blurMaskSampling)) { + flags |= eTraversalNeeded; + } + } + if (what & layer_state_t::eBlurMaskAlphaThresholdChanged) { + if (layer->setBlurMaskAlphaThreshold(s.blurMaskAlphaThreshold)) { + flags |= eTraversalNeeded; + } + } if (what & layer_state_t::eSizeChanged) { if (layer->setSize(s.w, s.h)) { flags |= eTraversalNeeded; @@ -2309,6 +2421,11 @@ status_t SurfaceFlinger::createLayer( name, w, h, flags, handle, gbp, &layer); break; + case ISurfaceComposerClient::eFXSurfaceBlur: + result = createBlurLayer(client, + name, w, h, flags, + handle, gbp, &layer); + break; default: result = BAD_VALUE; break; @@ -2342,7 +2459,7 @@ status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client, break; } - *outLayer = new Layer(this, client, name, w, h, flags); + *outLayer = DisplayUtils::getInstance()->getLayerInstance(this, client, name, w, h, flags); status_t err = (*outLayer)->setBuffers(w, h, format, flags); if (err == NO_ERROR) { *handle = (*outLayer)->getHandle(); @@ -2363,6 +2480,16 @@ status_t SurfaceFlinger::createDimLayer(const sp<Client>& client, return NO_ERROR; } +status_t SurfaceFlinger::createBlurLayer(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 LayerBlur(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 @@ -2605,14 +2732,19 @@ void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index if (name.isEmpty()) { mAnimFrameTracker.dumpStats(result); } else { + bool found = false; 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()) { + found = true; layer->dumpFrameStats(result); } } + if (!found && !strncmp(name.string(), "SurfaceView", 11)) { + lastSurfaceViewLayer->dumpFrameStats(result); + } } } @@ -2820,7 +2952,8 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, result.appendFormat(" h/w composer %s and %s\n", hwc.initCheck()==NO_ERROR ? "present" : "not present", (mDebugDisableHWC || mDebugRegion || mDaltonize - || mHasColorMatrix) ? "disabled" : "enabled"); + || mHasColorMatrix + || mHasSecondaryColorMatrix) ? "disabled" : "enabled"); hwc.dump(result); /* @@ -2841,7 +2974,7 @@ SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) { } } if (dpy == NULL) { - ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id); + ALOGW("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id); // Just use the primary display so we have something to return dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY); } @@ -3020,14 +3153,38 @@ status_t SurfaceFlinger::onTransact( } case 1018: { // Modify Choreographer's phase offset n = data.readInt32(); - mEventThread->setPhaseOffset(static_cast<nsecs_t>(n)); + if (mEventThread != NULL) + 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)); + if (mSFEventThread != NULL) + mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n)); return NO_ERROR; } + case 1030: { + // apply a secondary color matrix + // this will be combined with any other transformations + n = data.readInt32(); + mHasSecondaryColorMatrix = 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++) { + mSecondaryColorMatrix[i][j] = data.readFloat(); + } + } + } else { + mSecondaryColorMatrix = mat4(); + } + invalidateHwcGeometry(); + repaintEverything(); + return NO_ERROR; + } + } } return err; @@ -3155,7 +3312,8 @@ 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) { + bool useIdentityTransform, ISurfaceComposer::Rotation rotation, + bool useReadPixels) { if (CC_UNLIKELY(display == 0)) return BAD_VALUE; @@ -3205,6 +3363,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, uint32_t minLayerZ,maxLayerZ; bool useIdentityTransform; Transform::orientation_flags rotation; + bool useReadPixels; status_t result; public: MessageCaptureScreen(SurfaceFlinger* flinger, @@ -3212,12 +3371,14 @@ 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, Transform::orientation_flags rotation) + bool useIdentityTransform, Transform::orientation_flags rotation, + bool useReadPixels) : flinger(flinger), display(display), producer(producer), sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight), minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), useIdentityTransform(useIdentityTransform), rotation(rotation), + useReadPixels(useReadPixels), result(PERMISSION_DENIED) { } @@ -3227,9 +3388,10 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, virtual bool handler() { Mutex::Autolock _l(flinger->mStateLock); sp<const DisplayDevice> hw(flinger->getDisplayDevice(display)); + bool useReadPixels = this->useReadPixels && !flinger->mGpuToCpuSupported; result = flinger->captureScreenImplLocked(hw, producer, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, - useIdentityTransform, rotation); + useIdentityTransform, rotation, useReadPixels); static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result); return true; } @@ -3252,7 +3414,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, sp<MessageBase> msg = new MessageCaptureScreen(this, display, IGraphicBufferProducer::asInterface( wrapper ), sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, - useIdentityTransform, rotationFlags); + useIdentityTransform, rotationFlags, useReadPixels); status_t res = postMessageAsync(msg); if (res == NO_ERROR) { @@ -3301,6 +3463,12 @@ void SurfaceFlinger::renderScreenImplLocked( // make sure to clear all GL error flags engine.checkErrors(); + if (DisplayDevice::DISPLAY_PRIMARY == hw->getDisplayType() && + hw->isPanelInverseMounted()) { + rotation = (Transform::orientation_flags) + (rotation ^ Transform::ROT_180); + } + // set-up our viewport engine.setViewportAndProjection( reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation); @@ -3316,7 +3484,7 @@ void SurfaceFlinger::renderScreenImplLocked( const Layer::State& state(layer->getDrawingState()); if (state.layerStack == hw->getLayerStack()) { if (state.z >= minLayerZ && state.z <= maxLayerZ) { - if (layer->isVisible()) { + if (canDrawLayerinScreenShot(hw,layer)) { if (filtering) layer->setFiltering(true); layer->draw(hw, useIdentityTransform); if (filtering) layer->setFiltering(false); @@ -3336,7 +3504,8 @@ status_t SurfaceFlinger::captureScreenImplLocked( 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 useIdentityTransform, Transform::orientation_flags rotation, + bool useReadPixels) { ATRACE_CALL(); @@ -3354,6 +3523,8 @@ status_t SurfaceFlinger::captureScreenImplLocked( return BAD_VALUE; } + ++mActiveFrameSequence; + reqWidth = (!reqWidth) ? hw_w : reqWidth; reqHeight = (!reqHeight) ? hw_h : reqHeight; @@ -3388,7 +3559,8 @@ status_t SurfaceFlinger::captureScreenImplLocked( 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); + RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image, + useReadPixels, reqWidth, reqHeight); 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 @@ -3435,6 +3607,15 @@ status_t SurfaceFlinger::captureScreenImplLocked( ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError()); } } + if (useReadPixels) { + sp<GraphicBuffer> buf = static_cast<GraphicBuffer*>(buffer); + void* vaddr; + if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &vaddr) == NO_ERROR) { + getRenderEngine().readPixels(0, 0, buffer->stride, reqHeight, + (uint32_t *)vaddr); + buf->unlock(); + } + } if (DEBUG_SCREENSHOTS) { uint32_t* pixels = new uint32_t[reqWidth*reqHeight]; getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels); @@ -3492,6 +3673,44 @@ void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* v } } +/* ------------------------------------------------------------------------ + * Extensions + */ + +bool SurfaceFlinger::updateLayerVisibleNonTransparentRegion(const int& /*dpy*/, + const sp<Layer>& layer, bool& /*bIgnoreLayers*/, int& /*indexLOI*/, + uint32_t layerStack, const int& /*i*/) { + + const Layer::State& s(layer->getDrawingState()); + + // only consider the layers on the given layer stack + if (s.layerStack != layerStack) { + /* set the visible region as empty since we have removed the + * layerstack check in rebuildLayerStack() function + */ + Region visibleNonTransRegion; + visibleNonTransRegion.set(Rect(0,0)); + layer->setVisibleNonTransparentRegion(visibleNonTransRegion); + + return true; + } + + return false; +} + +bool SurfaceFlinger::canDrawLayerinScreenShot( + const sp<const DisplayDevice>& /*hw*/, + const sp<Layer>& layer) { + return layer->isVisible(); +} + +void SurfaceFlinger::drawWormHoleIfRequired(HWComposer::LayerListIterator& /*cur*/, + const HWComposer::LayerListIterator& /*end*/, + const sp<const DisplayDevice>& hw, + const Region& region) { + drawWormhole(hw, region); +} + // --------------------------------------------------------------------------- SurfaceFlinger::LayerVector::LayerVector() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b3baadd..20d65c1 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -56,6 +56,8 @@ #include "DisplayHardware/HWComposer.h" #include "Effects/Daltonizer.h" +#include "FrameRateHelper.h" + namespace android { // --------------------------------------------------------------------------- @@ -66,6 +68,7 @@ class EventThread; class IGraphicBufferAlloc; class Layer; class LayerDim; +class LayerBlur; class Surface; class RenderEngine; class EventControlThread; @@ -84,6 +87,10 @@ class SurfaceFlinger : public BnSurfaceComposer, private HWComposer::EventHandler { public: +#ifdef QTI_BSP + friend class ExSurfaceFlinger; +#endif + static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; } @@ -138,7 +145,9 @@ private: friend class Client; friend class DisplayEventConnection; friend class Layer; + friend class LayerDim; friend class MonitoredProducer; + friend class LayerBlur; // This value is specified in number of frames. Log frame stats at most // every half hour. @@ -207,7 +216,8 @@ private: const sp<IGraphicBufferProducer>& producer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ, - bool useIdentityTransform, ISurfaceComposer::Rotation rotation); + bool useIdentityTransform, ISurfaceComposer::Rotation rotation, + bool isCpuConsumer); virtual status_t getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats); virtual status_t getDisplayConfigs(const sp<IBinder>& display, @@ -235,6 +245,43 @@ private: virtual void onHotplugReceived(int disp, bool connected); /* ------------------------------------------------------------------------ + * Extensions + */ + virtual void updateExtendedMode() { } + + virtual void getIndexLOI(size_t /*dpy*/, + const LayerVector& /*currentLayers*/, + bool& /*bIgnoreLayers*/, + int& /*indexLOI*/) { } + + virtual bool updateLayerVisibleNonTransparentRegion( + const int& dpy, const sp<Layer>& layer, + bool& bIgnoreLayers, int& indexLOI, + uint32_t layerStack, const int& i); + + virtual void delayDPTransactionIfNeeded( + const Vector<DisplayState>& /*displays*/) { } + + virtual bool canDrawLayerinScreenShot( + const sp<const DisplayDevice>& hw, + const sp<Layer>& layer); + + virtual void isfreezeSurfacePresent( + bool& freezeSurfacePresent, + const sp<const DisplayDevice>& /*hw*/, + const int32_t& /*id*/) { freezeSurfacePresent = false; } + + virtual void setOrientationEventControl( + bool& /*freezeSurfacePresent*/, + const int32_t& /*id*/) { } + + virtual void updateVisibleRegionsDirty() { } + + virtual void drawWormHoleIfRequired(HWComposer::LayerListIterator &cur, + const HWComposer::LayerListIterator &end, + const sp<const DisplayDevice>& hw, + const Region& region); + /* ------------------------------------------------------------------------ * Message handling */ void waitForEvent(); @@ -294,6 +341,10 @@ private: uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer); + status_t createBlurLayer(const sp<Client>& client, const String8& name, + uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle, + sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer); + // called in response to the window-manager calling // ISurfaceComposerClient::destroySurface() status_t onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle); @@ -329,7 +380,8 @@ private: 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 useIdentityTransform, Transform::orientation_flags rotation, + bool useReadPixels); /* ------------------------------------------------------------------------ * EGL @@ -373,7 +425,7 @@ private: * Compositing */ void invalidateHwcGeometry(); - static void computeVisibleRegions( + void computeVisibleRegions(size_t dpy, const LayerVector& currentLayers, uint32_t layerStack, Region& dirtyRegion, Region& opaqueRegion); @@ -419,6 +471,7 @@ private: void logFrameStats(); void dumpStaticScreenStats(String8& result) const; + virtual void dumpDrawCycle(bool /* prePrepare */ ) { } /* ------------------------------------------------------------------------ * Attributes @@ -500,12 +553,26 @@ private: mat4 mColorMatrix; bool mHasColorMatrix; + mat4 mSecondaryColorMatrix; + bool mHasSecondaryColorMatrix; + // Static screen stats bool mHasPoweredOff; static const size_t NUM_BUCKETS = 8; // < 1-7, 7+ nsecs_t mFrameBuckets[NUM_BUCKETS]; nsecs_t mTotalTime; nsecs_t mLastSwapTime; + + FrameRateHelper mFrameRateHelper; + + /* + * A number that increases on every new frame composition and screen capture. + * LayerBlur can speed up it's drawing by caching texture using this variable + * if multiple LayerBlur objects draw in one frame composition. + * In case of display mirroring, this variable should be increased on every display. + */ + uint32_t mActiveFrameSequence; + }; }; // namespace android diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp index a74bc4c..e8464a3 100644 --- a/services/surfaceflinger/main_surfaceflinger.cpp +++ b/services/surfaceflinger/main_surfaceflinger.cpp @@ -22,6 +22,7 @@ #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include "SurfaceFlinger.h" +#include "DisplayUtils.h" using namespace android; @@ -35,12 +36,19 @@ int main(int, char**) { ps->startThreadPool(); // instantiate surfaceflinger - sp<SurfaceFlinger> flinger = new SurfaceFlinger(); + sp<SurfaceFlinger> flinger = DisplayUtils::getInstance()->getSFInstance(); setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY); set_sched_policy(0, SP_FOREGROUND); +#ifdef ENABLE_CPUSETS + // Put most SurfaceFlinger threads in the system-background cpuset + // Keeps us from unnecessarily using big cores + // Do this after the binder thread pool init + set_cpuset_policy(0, SP_SYSTEM); +#endif + // initialize before clients can connect flinger->init(); |