Switch SurfaceFlinger to HWC 2.0
Enables SurfaceFlinger to speak to version 2.0 of the Hardware Composer
HAL instead of version 1.x (also removing support for the framebuffer
HAL). By default, however, this functionality is disabled. In order to
enable it, USE_HWC2 must be set to true in Android.mk.
Change-Id: I4589e02ac2165236b10ff2f7cb772f87e0d3daab
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 61f631f..8de3302 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -110,7 +110,7 @@
// when the current buffer is released by updateTexImage(). Multiple
// fences can be set for a given buffer; they will be merged into a single
// union fence.
- void setReleaseFence(const sp<Fence>& fence);
+ virtual void setReleaseFence(const sp<Fence>& fence);
// getTransformMatrix retrieves the 4x4 texture coordinate transform matrix
// associated with the texture image set by the most recent call to
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 3d71aa8..8cc9fc1 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -15,13 +15,11 @@
LayerDim.cpp \
MessageQueue.cpp \
MonitoredProducer.cpp \
- SurfaceFlinger.cpp \
SurfaceFlingerConsumer.cpp \
Transform.cpp \
DisplayHardware/FramebufferSurface.cpp \
DisplayHardware/HWC2.cpp \
DisplayHardware/HWC2On1Adapter.cpp \
- DisplayHardware/HWComposer.cpp \
DisplayHardware/PowerHAL.cpp \
DisplayHardware/VirtualDisplaySurface.cpp \
Effects/Daltonizer.cpp \
@@ -42,6 +40,19 @@
LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+USE_HWC2 := false
+ifeq ($(USE_HWC2),true)
+ LOCAL_CFLAGS += -DUSE_HWC2
+ LOCAL_SRC_FILES += \
+ SurfaceFlinger.cpp \
+ DisplayHardware/HWComposer.cpp
+else
+ LOCAL_SRC_FILES += \
+ SurfaceFlinger_hwc1.cpp \
+ DisplayHardware/HWComposer_hwc1.cpp
+endif
+
ifeq ($(TARGET_BOARD_PLATFORM),omap4)
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
endif
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index e9cbbca..8d8e40d 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// #define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "DisplayDevice"
+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -33,6 +37,9 @@
#include "DisplayHardware/DisplaySurface.h"
#include "DisplayHardware/HWComposer.h"
+#ifdef USE_HWC2
+#include "DisplayHardware/HWC2.h"
+#endif
#include "RenderEngine/RenderEngine.h"
#include "clz.h"
@@ -65,7 +72,9 @@
const sp<SurfaceFlinger>& flinger,
DisplayType type,
int32_t hwcId,
+#ifndef USE_HWC2
int format,
+#endif
bool isSecure,
const wp<IBinder>& displayToken,
const sp<DisplaySurface>& displaySurface,
@@ -73,12 +82,17 @@
EGLConfig config)
: lastCompositionHadVisibleLayers(false),
mFlinger(flinger),
- mType(type), mHwcDisplayId(hwcId),
+ mType(type),
+ mHwcDisplayId(hwcId),
mDisplayToken(displayToken),
mDisplaySurface(displaySurface),
mDisplay(EGL_NO_DISPLAY),
mSurface(EGL_NO_SURFACE),
- mDisplayWidth(), mDisplayHeight(), mFormat(),
+ mDisplayWidth(),
+ mDisplayHeight(),
+#ifndef USE_HWC2
+ mFormat(),
+#endif
mFlags(),
mPageFlipCount(),
mIsSecure(isSecure),
@@ -98,7 +112,11 @@
EGLSurface eglSurface;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (config == EGL_NO_CONFIG) {
+#ifdef USE_HWC2
+ config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888);
+#else
config = RenderEngine::chooseEglConfig(display, format);
+#endif
}
eglSurface = eglCreateWindowSurface(display, config, window, NULL);
eglQuerySurface(display, eglSurface, EGL_WIDTH, &mDisplayWidth);
@@ -117,7 +135,9 @@
mConfig = config;
mDisplay = display;
mSurface = eglSurface;
- mFormat = format;
+#ifndef USE_HWC2
+ mFormat = format;
+#endif
mPageFlipCount = 0;
mViewport.makeInvalid();
mFrame.makeInvalid();
@@ -158,8 +178,10 @@
void DisplayDevice::disconnect(HWComposer& hwc) {
if (mHwcDisplayId >= 0) {
hwc.disconnectDisplay(mHwcDisplayId);
+#ifndef USE_HWC2
if (mHwcDisplayId >= DISPLAY_VIRTUAL)
hwc.freeDisplayId(mHwcDisplayId);
+#endif
mHwcDisplayId = -1;
}
}
@@ -176,9 +198,11 @@
return mDisplayHeight;
}
+#ifndef USE_HWC2
PixelFormat DisplayDevice::getFormat() const {
return mFormat;
}
+#endif
EGLSurface DisplayDevice::getEGLSurface() const {
return mSurface;
@@ -195,9 +219,11 @@
return mPageFlipCount;
}
+#ifndef USE_HWC2
status_t DisplayDevice::compositionComplete() const {
return mDisplaySurface->compositionComplete();
}
+#endif
void DisplayDevice::flip(const Region& dirty) const
{
@@ -219,6 +245,31 @@
return mDisplaySurface->beginFrame(mustRecompose);
}
+#ifdef USE_HWC2
+status_t DisplayDevice::prepareFrame(HWComposer& hwc) {
+ status_t error = hwc.prepare(*this);
+ if (error != NO_ERROR) {
+ return error;
+ }
+
+ DisplaySurface::CompositionType compositionType;
+ bool hasClient = hwc.hasClientComposition(mHwcDisplayId);
+ bool hasDevice = hwc.hasDeviceComposition(mHwcDisplayId);
+ if (hasClient && hasDevice) {
+ compositionType = DisplaySurface::COMPOSITION_MIXED;
+ } else if (hasClient) {
+ compositionType = DisplaySurface::COMPOSITION_GLES;
+ } else if (hasDevice) {
+ compositionType = DisplaySurface::COMPOSITION_HWC;
+ } else {
+ // Nothing to do -- when turning the screen off we get a frame like
+ // this. Call it a HWC frame since we won't be doing any GLES work but
+ // will do a prepare/set cycle.
+ compositionType = DisplaySurface::COMPOSITION_HWC;
+ }
+ return mDisplaySurface->prepareFrame(compositionType);
+}
+#else
status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const {
DisplaySurface::CompositionType compositionType;
bool haveGles = hwc.hasGlesComposition(mHwcDisplayId);
@@ -237,8 +288,12 @@
}
return mDisplaySurface->prepareFrame(compositionType);
}
+#endif
void DisplayDevice::swapBuffers(HWComposer& hwc) const {
+#ifdef USE_HWC2
+ if (hwc.hasClientComposition(mHwcDisplayId)) {
+#else
// We need to call eglSwapBuffers() if:
// (1) we don't have a hardware composer, or
// (2) we did GLES composition this frame, and either
@@ -248,6 +303,7 @@
if (hwc.initCheck() != NO_ERROR ||
(hwc.hasGlesComposition(mHwcDisplayId) &&
(hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) {
+#endif
EGLBoolean success = eglSwapBuffers(mDisplay, mSurface);
if (!success) {
EGLint error = eglGetError();
@@ -269,11 +325,17 @@
}
}
+#ifdef USE_HWC2
+void DisplayDevice::onSwapBuffersCompleted() const {
+ mDisplaySurface->onFrameCommitted();
+}
+#else
void DisplayDevice::onSwapBuffersCompleted(HWComposer& hwc) const {
if (hwc.initCheck() == NO_ERROR) {
mDisplaySurface->onFrameCommitted();
}
}
+#endif
uint32_t DisplayDevice::getFlags() const
{
@@ -302,6 +364,12 @@
false, Transform::ROT_0);
}
+#ifdef USE_HWC2
+const sp<Fence>& DisplayDevice::getClientTargetAcquireFence() const {
+ return mDisplaySurface->getClientTargetAcquireFence();
+}
+#endif
+
// ----------------------------------------------------------------------------
void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers) {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 6d380d1..38241d9 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -17,21 +17,31 @@
#ifndef ANDROID_DISPLAY_DEVICE_H
#define ANDROID_DISPLAY_DEVICE_H
+#include "Transform.h"
+
#include <stdlib.h>
+#ifndef USE_HWC2
#include <ui/PixelFormat.h>
+#endif
#include <ui/Region.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
+#ifdef USE_HWC2
+#include <binder/IBinder.h>
+#include <utils/RefBase.h>
+#endif
#include <utils/Mutex.h>
#include <utils/String8.h>
#include <utils/Timers.h>
#include <hardware/hwcomposer_defs.h>
-#include "Transform.h"
+#ifdef USE_HWC2
+#include <memory>
+#endif
struct ANativeWindow;
@@ -39,6 +49,9 @@
struct DisplayInfo;
class DisplaySurface;
+#ifdef USE_HWC2
+class Fence;
+#endif
class IGraphicBufferProducer;
class Layer;
class SurfaceFlinger;
@@ -75,8 +88,10 @@
DisplayDevice(
const sp<SurfaceFlinger>& flinger,
DisplayType type,
- int32_t hwcId, // negative for non-HWC-composited displays
+ int32_t hwcId,
+#ifndef USE_HWC2
int format,
+#endif
bool isSecure,
const wp<IBinder>& displayToken,
const sp<DisplaySurface>& displaySurface,
@@ -99,7 +114,9 @@
int getWidth() const;
int getHeight() const;
+#ifndef USE_HWC2
PixelFormat getFormat() const;
+#endif
uint32_t getFlags() const;
EGLSurface getEGLSurface() const;
@@ -128,13 +145,23 @@
// We pass in mustRecompose so we can keep VirtualDisplaySurface's state
// machine happy without actually queueing a buffer if nothing has changed
status_t beginFrame(bool mustRecompose) const;
+#ifdef USE_HWC2
+ status_t prepareFrame(HWComposer& hwc);
+#else
status_t prepareFrame(const HWComposer& hwc) const;
+#endif
void swapBuffers(HWComposer& hwc) const;
+#ifndef USE_HWC2
status_t compositionComplete() const;
+#endif
// called after h/w composer has completed its set() call
+#ifdef USE_HWC2
+ void onSwapBuffersCompleted() const;
+#else
void onSwapBuffersCompleted(HWComposer& hwc) const;
+#endif
Rect getBounds() const {
return Rect(mDisplayWidth, mDisplayHeight);
@@ -147,6 +174,10 @@
EGLBoolean makeCurrent(EGLDisplay dpy, EGLContext ctx) const;
void setViewportAndProjection() const;
+#ifdef USE_HWC2
+ const sp<Fence>& getClientTargetAcquireFence() const;
+#endif
+
/* ------------------------------------------------------------------------
* Display power mode management.
*/
@@ -187,7 +218,9 @@
EGLSurface mSurface;
int mDisplayWidth;
int mDisplayHeight;
+#ifndef USE_HWC2
PixelFormat mFormat;
+#endif
uint32_t mFlags;
mutable uint32_t mPageFlipCount;
String8 mDisplayName;
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
index 2f743c1..d819f83 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
@@ -49,11 +49,13 @@
};
virtual status_t prepareFrame(CompositionType compositionType) = 0;
+#ifndef USE_HWC2
// Should be called when composition rendering is complete for a frame (but
// eglSwapBuffers hasn't necessarily been called). Required by certain
// older drivers for synchronization.
// TODO: Remove this when we drop support for HWC 1.0.
virtual status_t compositionComplete() = 0;
+#endif
// Inform the surface that GLES composition is complete for this frame, and
// the surface should make sure that HWComposer has the correct buffer for
@@ -74,6 +76,10 @@
virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0;
+#ifdef USE_HWC2
+ virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
+#endif
+
protected:
DisplaySurface() {}
virtual ~DisplaySurface() {}
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index a6bc158..29e0766 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -15,6 +15,10 @@
** limitations under the License.
*/
+// #define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "FramebufferSurface"
+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -56,16 +60,35 @@
ConsumerBase(consumer),
mDisplayType(disp),
mCurrentBufferSlot(-1),
+#ifdef USE_HWC2
+ mCurrentBuffer(),
+ mCurrentFence(Fence::NO_FENCE),
+ mHwc(hwc),
+ mHasPendingRelease(false),
+ mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mPreviousBuffer()
+#else
mCurrentBuffer(0),
mHwc(hwc)
+#endif
{
+#ifdef USE_HWC2
+ ALOGV("Creating for display %d", disp);
+#endif
+
mName = "FramebufferSurface";
mConsumer->setConsumerName(mName);
mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_COMPOSER);
+#ifdef USE_HWC2
+ const auto& activeConfig = mHwc.getActiveConfig(disp);
+ mConsumer->setDefaultBufferSize(activeConfig->getWidth(),
+ activeConfig->getHeight());
+#else
mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp));
- mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp));
+ mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp));
+#endif
mConsumer->setMaxAcquiredBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS - 1);
}
@@ -78,13 +101,35 @@
}
status_t FramebufferSurface::advanceFrame() {
+#ifdef USE_HWC2
+ sp<GraphicBuffer> buf;
+ sp<Fence> acquireFence(Fence::NO_FENCE);
+ android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
+ status_t result = nextBuffer(buf, acquireFence, dataspace);
+ if (result != NO_ERROR) {
+ ALOGE("error latching next FramebufferSurface buffer: %s (%d)",
+ strerror(-result), result);
+ return result;
+ }
+ result = mHwc.setClientTarget(mDisplayType, acquireFence, buf, dataspace);
+ if (result != NO_ERROR) {
+ ALOGE("error posting framebuffer: %d", result);
+ }
+ return result;
+#else
// Once we remove FB HAL support, we can call nextBuffer() from here
// instead of using onFrameAvailable(). No real benefit, except it'll be
// more like VirtualDisplaySurface.
return NO_ERROR;
+#endif
}
+#ifdef USE_HWC2
+status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer,
+ sp<Fence>& outFence, android_dataspace_t& outDataspace) {
+#else
status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence) {
+#endif
Mutex::Autolock lock(mMutex);
BufferItem item;
@@ -107,6 +152,11 @@
// had released the old buffer first.
if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT &&
item.mSlot != mCurrentBufferSlot) {
+#ifdef USE_HWC2
+ mHasPendingRelease = true;
+ mPreviousBufferSlot = mCurrentBufferSlot;
+ mPreviousBuffer = mCurrentBuffer;
+#else
// Release the previous buffer.
err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
@@ -114,14 +164,23 @@
ALOGE("error releasing buffer: %s (%d)", strerror(-err), err);
return err;
}
+#endif
}
mCurrentBufferSlot = item.mSlot;
mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
+#ifdef USE_HWC2
+ mCurrentFence = item.mFence;
+#endif
+
outFence = item.mFence;
outBuffer = mCurrentBuffer;
+#ifdef USE_HWC2
+ outDataspace = item.mDataSpace;
+#endif
return NO_ERROR;
}
+#ifndef USE_HWC2
// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl.
void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) {
sp<GraphicBuffer> buf;
@@ -137,6 +196,7 @@
ALOGE("error posting framebuffer: %d", err);
}
}
+#endif
void FramebufferSurface::freeBufferLocked(int slotIndex) {
ConsumerBase::freeBufferLocked(slotIndex);
@@ -146,6 +206,24 @@
}
void FramebufferSurface::onFrameCommitted() {
+#ifdef USE_HWC2
+ if (mHasPendingRelease) {
+ sp<Fence> fence = mHwc.getRetireFence(mDisplayType);
+ if (fence->isValid()) {
+ status_t result = addReleaseFence(mPreviousBufferSlot,
+ mPreviousBuffer, fence);
+ ALOGE_IF(result != NO_ERROR, "onFrameCommitted: failed to add the"
+ " fence: %s (%d)", strerror(-result), result);
+ }
+ status_t result = releaseBufferLocked(mPreviousBufferSlot,
+ mPreviousBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+ ALOGE_IF(result != NO_ERROR, "onFrameCommitted: error releasing buffer:"
+ " %s (%d)", strerror(-result), result);
+
+ mPreviousBuffer.clear();
+ mHasPendingRelease = false;
+ }
+#else
sp<Fence> fence = mHwc.getAndResetReleaseFence(mDisplayType);
if (fence->isValid() &&
mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) {
@@ -154,12 +232,15 @@
ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)",
strerror(-err), err);
}
+#endif
}
+#ifndef USE_HWC2
status_t FramebufferSurface::compositionComplete()
{
return mHwc.fbCompositionComplete();
}
+#endif
void FramebufferSurface::dumpAsString(String8& result) const {
ConsumerBase::dump(result);
@@ -167,10 +248,18 @@
void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const
{
+#ifndef USE_HWC2
mHwc.fbDump(result);
+#endif
ConsumerBase::dumpLocked(result, prefix);
}
+#ifdef USE_HWC2
+const sp<Fence>& FramebufferSurface::getClientTargetAcquireFence() const {
+ return mCurrentFence;
+}
+#endif
+
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 3d17840..0605602 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -41,7 +41,9 @@
virtual status_t beginFrame(bool mustRecompose);
virtual status_t prepareFrame(CompositionType compositionType);
+#ifndef USE_HWC2
virtual status_t compositionComplete();
+#endif
virtual status_t advanceFrame();
virtual void onFrameCommitted();
virtual void dumpAsString(String8& result) const;
@@ -50,10 +52,16 @@
// displays.
virtual void resizeBuffers(const uint32_t /*w*/, const uint32_t /*h*/) { };
+#ifdef USE_HWC2
+ virtual const sp<Fence>& getClientTargetAcquireFence() const override;
+#endif
+
private:
virtual ~FramebufferSurface() { }; // this class cannot be overloaded
+#ifndef USE_HWC2
virtual void onFrameAvailable(const BufferItem& item);
+#endif
virtual void freeBufferLocked(int slotIndex);
virtual void dumpLocked(String8& result, const char* prefix) const;
@@ -61,7 +69,12 @@
// nextBuffer waits for and then latches the next buffer from the
// BufferQueue and releases the previously latched buffer to the
// BufferQueue. The new buffer is returned in the 'buffer' argument.
+#ifdef USE_HWC2
+ status_t nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence,
+ android_dataspace_t& outDataspace);
+#else
status_t nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence);
+#endif
// mDisplayType must match one of the HWC display types
int mDisplayType;
@@ -75,8 +88,20 @@
// no current buffer.
sp<GraphicBuffer> mCurrentBuffer;
+#ifdef USE_HWC2
+ // mCurrentFence is the current buffer's acquire fence
+ sp<Fence> mCurrentFence;
+#endif
+
// Hardware composer, owned by SurfaceFlinger.
HWComposer& mHwc;
+
+#ifdef USE_HWC2
+ // Previous buffer to release after getting an updated retire fence
+ bool mHasPendingRelease;
+ int mPreviousBufferSlot;
+ sp<GraphicBuffer> mPreviousBuffer;
+#endif
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index d37fcb2..26f9519 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// #define LOG_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "HWComposer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <inttypes.h>
@@ -43,6 +47,8 @@
#include <cutils/properties.h>
#include "HWComposer.h"
+#include "HWC2On1Adapter.h"
+#include "HWC2.h"
#include "../Layer.h" // needed only for debugging
#include "../SurfaceFlinger.h"
@@ -51,1088 +57,688 @@
#define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION
-static uint32_t hwcApiVersion(const hwc_composer_device_1_t* hwc) {
- uint32_t hwcVersion = hwc->common.version;
- return hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
-}
-
-static uint32_t hwcHeaderVersion(const hwc_composer_device_1_t* hwc) {
- uint32_t hwcVersion = hwc->common.version;
- return hwcVersion & HARDWARE_API_VERSION_2_HEADER_MASK;
-}
-
-static bool hwcHasApiVersion(const hwc_composer_device_1_t* hwc,
- uint32_t version) {
- return hwcApiVersion(hwc) >= (version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK);
-}
-
// ---------------------------------------------------------------------------
-struct HWComposer::cb_context {
- struct callbacks : public hwc_procs_t {
- // these are here to facilitate the transition when adding
- // new callbacks (an implementation can check for NULL before
- // calling a new callback).
- void (*zero[4])(void);
- };
- callbacks procs;
- HWComposer* hwc;
-};
-
-// ---------------------------------------------------------------------------
-
-HWComposer::HWComposer(
- const sp<SurfaceFlinger>& flinger,
- EventHandler& handler)
+HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger)
: mFlinger(flinger),
- mFbDev(0), mHwc(0), mNumDisplays(1),
- mCBContext(new cb_context),
- mEventHandler(handler),
- mDebugForceFakeVSync(false)
+ mAdapter(),
+ mHwcDevice(),
+ mDisplayData(2),
+ mFreeDisplaySlots(),
+ mHwcDisplaySlots(),
+ mCBContext(),
+ mEventHandler(nullptr),
+ mVSyncCounts(),
+ mRemainingHwcVirtualDisplays(0)
{
- for (size_t i =0 ; i<MAX_HWC_DISPLAYS ; i++) {
- mLists[i] = 0;
- }
-
for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) {
mLastHwVSync[i] = 0;
mVSyncCounts[i] = 0;
}
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.sf.no_hw_vsync", value, "0");
- mDebugForceFakeVSync = atoi(value);
-
- bool needVSyncThread = true;
-
- // Note: some devices may insist that the FB HAL be opened before HWC.
- int fberr = loadFbHalModule();
loadHwcModule();
-
- if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
- // close FB HAL if we don't needed it.
- // FIXME: this is temporary until we're not forced to open FB HAL
- // before HWC.
- framebuffer_close(mFbDev);
- mFbDev = NULL;
- }
-
- // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory.
- if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
- && !mFbDev) {
- ALOGE("ERROR: failed to open framebuffer (%s), aborting",
- strerror(-fberr));
- abort();
- }
-
- // these display IDs are always reserved
- for (size_t i=0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {
- mAllocatedDisplayIDs.markBit(i);
- }
-
- if (mHwc) {
- ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
- (hwcApiVersion(mHwc) >> 24) & 0xff,
- (hwcApiVersion(mHwc) >> 16) & 0xff);
- if (mHwc->registerProcs) {
- mCBContext->hwc = this;
- mCBContext->procs.invalidate = &hook_invalidate;
- mCBContext->procs.vsync = &hook_vsync;
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
- mCBContext->procs.hotplug = &hook_hotplug;
- else
- mCBContext->procs.hotplug = NULL;
- memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
- mHwc->registerProcs(mHwc, &mCBContext->procs);
- }
-
- // don't need a vsync thread if we have a hardware composer
- needVSyncThread = false;
- // always turn vsync off when we start
- eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
-
- // the number of displays we actually have depends on the
- // hw composer version
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
- // 1.3 adds support for virtual displays
- mNumDisplays = MAX_HWC_DISPLAYS;
- } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
- // 1.1 adds support for multiple displays
- mNumDisplays = NUM_BUILTIN_DISPLAYS;
- } else {
- mNumDisplays = 1;
- }
- }
-
- if (mFbDev) {
- ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)),
- "should only have fbdev if no hwc or hwc is 1.0");
-
- DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
- disp.connected = true;
- disp.format = mFbDev->format;
- DisplayConfig config = DisplayConfig();
- config.width = mFbDev->width;
- config.height = mFbDev->height;
- config.xdpi = mFbDev->xdpi;
- config.ydpi = mFbDev->ydpi;
- config.refresh = nsecs_t(1e9 / mFbDev->fps);
- disp.configs.push_back(config);
- disp.currentConfig = 0;
- } else if (mHwc) {
- // here we're guaranteed to have at least HWC 1.1
- for (size_t i =0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {
- queryDisplayProperties(i);
- }
- }
-
- if (needVSyncThread) {
- // we don't have VSYNC support, we need to fake it
- mVSyncThread = new VSyncThread(*this);
- }
}
-HWComposer::~HWComposer() {
- if (mHwc) {
- eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
+HWComposer::~HWComposer() {}
+
+void HWComposer::setEventHandler(EventHandler* handler)
+{
+ if (handler == nullptr) {
+ ALOGE("setEventHandler: Rejected attempt to clear handler");
+ return;
}
- if (mVSyncThread != NULL) {
- mVSyncThread->requestExitAndWait();
+
+ bool wasNull = (mEventHandler == nullptr);
+ mEventHandler = handler;
+
+ if (wasNull) {
+ auto hotplugHook = std::bind(&HWComposer::hotplug, this,
+ std::placeholders::_1, std::placeholders::_2);
+ mHwcDevice->registerHotplugCallback(hotplugHook);
+ auto invalidateHook = std::bind(&HWComposer::invalidate, this,
+ std::placeholders::_1);
+ mHwcDevice->registerRefreshCallback(invalidateHook);
+ auto vsyncHook = std::bind(&HWComposer::vsync, this,
+ std::placeholders::_1, std::placeholders::_2);
+ mHwcDevice->registerVsyncCallback(vsyncHook);
}
- if (mHwc) {
- hwc_close_1(mHwc);
- }
- if (mFbDev) {
- framebuffer_close(mFbDev);
- }
- delete mCBContext;
}
// Load and prepare the hardware composer module. Sets mHwc.
void HWComposer::loadHwcModule()
{
+ ALOGV("loadHwcModule");
+
hw_module_t const* module;
if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
- ALOGE("%s module not found", HWC_HARDWARE_MODULE_ID);
- return;
+ ALOGE("%s module not found, aborting", HWC_HARDWARE_MODULE_ID);
+ abort();
}
- int err = hwc_open_1(module, &mHwc);
- if (err) {
- ALOGE("%s device failed to initialize (%s)",
- HWC_HARDWARE_COMPOSER, strerror(-err));
- return;
+ if (module->module_api_version >= 0x0200) {
+ hwc2_device_t* hwc2device = nullptr;
+ int error = hwc2_open(module, &hwc2device);
+ if (error != 0) {
+ ALOGE("Failed to open HWC2 device (%s), aborting", strerror(-error));
+ abort();
+ }
+ mHwcDevice = std::make_unique<HWC2::Device>(hwc2device);
+ } else {
+ hwc_composer_device_1_t* hwc1device = nullptr;
+ int error = hwc_open_1(module, &hwc1device);
+ if (error) {
+ ALOGE("Failed to open HWC1 device (%s), aborting", strerror(-error));
+ abort();
+ }
+ mAdapter = std::make_unique<HWC2On1Adapter>(hwc1device);
+ uint8_t minorVersion = mAdapter->getHwc1MinorVersion();
+ if (minorVersion < 1) {
+ ALOGE("Cannot adapt to HWC version %d.%d",
+ static_cast<int32_t>((minorVersion >> 8) & 0xF),
+ static_cast<int32_t>(minorVersion & 0xF));
+ abort();
+ }
+ mHwcDevice = std::make_unique<HWC2::Device>(
+ static_cast<hwc2_device_t*>(mAdapter.get()));
}
- if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) ||
- hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION ||
- hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) {
- ALOGE("%s device version %#x unsupported, will not be used",
- HWC_HARDWARE_COMPOSER, mHwc->common.version);
- hwc_close_1(mHwc);
- mHwc = NULL;
- return;
+ mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount();
+}
+
+bool HWComposer::isValidDisplay(int32_t displayId) const {
+ return static_cast<size_t>(displayId) < mDisplayData.size() &&
+ mDisplayData[displayId].hwcDisplay;
+}
+
+void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) {
+ bool valid = true;
+ switch (from) {
+ case HWC2::Composition::Client:
+ valid = false;
+ break;
+ case HWC2::Composition::Device:
+ case HWC2::Composition::SolidColor:
+ valid = (to == HWC2::Composition::Client);
+ break;
+ case HWC2::Composition::Cursor:
+ case HWC2::Composition::Sideband:
+ valid = (to == HWC2::Composition::Client ||
+ to == HWC2::Composition::Device);
+ break;
+ default:
+ break;
+ }
+
+ if (!valid) {
+ ALOGE("Invalid layer type change: %s --> %s", to_string(from).c_str(),
+ to_string(to).c_str());
}
}
-// Load and prepare the FB HAL, which uses the gralloc module. Sets mFbDev.
-int HWComposer::loadFbHalModule()
-{
- hw_module_t const* module;
-
- int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
- if (err != 0) {
- ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID);
- return err;
+void HWComposer::hotplug(const std::shared_ptr<HWC2::Display>& display,
+ HWC2::Connection connected) {
+ ALOGV("hotplug: %" PRIu64 ", %s", display->getId(),
+ to_string(connected).c_str());
+ int32_t disp = 0;
+ if (!mDisplayData[0].hwcDisplay) {
+ ALOGE_IF(connected != HWC2::Connection::Connected, "Assumed primary"
+ " display would be connected");
+ mDisplayData[0].hwcDisplay = display;
+ mHwcDisplaySlots[display->getId()] = 0;
+ disp = DisplayDevice::DISPLAY_PRIMARY;
+ } else {
+ // Disconnect is handled through HWComposer::disconnectDisplay via
+ // SurfaceFlinger's onHotplugReceived callback handling
+ if (connected == HWC2::Connection::Connected) {
+ mDisplayData[1].hwcDisplay = display;
+ mHwcDisplaySlots[display->getId()] = 1;
+ }
+ disp = DisplayDevice::DISPLAY_EXTERNAL;
}
-
- return framebuffer_open(module, &mFbDev);
+ mEventHandler->onHotplugReceived(disp,
+ connected == HWC2::Connection::Connected);
}
-status_t HWComposer::initCheck() const {
- return mHwc ? NO_ERROR : NO_INIT;
-}
-
-void HWComposer::hook_invalidate(const struct hwc_procs* procs) {
- cb_context* ctx = reinterpret_cast<cb_context*>(
- const_cast<hwc_procs_t*>(procs));
- ctx->hwc->invalidate();
-}
-
-void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp,
- int64_t timestamp) {
- cb_context* ctx = reinterpret_cast<cb_context*>(
- const_cast<hwc_procs_t*>(procs));
- ctx->hwc->vsync(disp, timestamp);
-}
-
-void HWComposer::hook_hotplug(const struct hwc_procs* procs, int disp,
- int connected) {
- cb_context* ctx = reinterpret_cast<cb_context*>(
- const_cast<hwc_procs_t*>(procs));
- ctx->hwc->hotplug(disp, connected);
-}
-
-void HWComposer::invalidate() {
+void HWComposer::invalidate(const std::shared_ptr<HWC2::Display>& /*display*/) {
mFlinger->repaintEverything();
}
-void HWComposer::vsync(int disp, int64_t timestamp) {
- if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
- {
- Mutex::Autolock _l(mLock);
-
- // There have been reports of HWCs that signal several vsync events
- // with the same timestamp when turning the display off and on. This
- // is a bug in the HWC implementation, but filter the extra events
- // out here so they don't cause havoc downstream.
- if (timestamp == mLastHwVSync[disp]) {
- ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
- timestamp);
- return;
- }
-
- mLastHwVSync[disp] = timestamp;
- }
-
- char tag[16];
- snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
- ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
-
- mEventHandler.onVSyncReceived(disp, timestamp);
- }
-}
-
-void HWComposer::hotplug(int disp, int connected) {
- if (disp >= VIRTUAL_DISPLAY_ID_BASE) {
- ALOGE("hotplug event received for invalid display: disp=%d connected=%d",
- disp, connected);
+void HWComposer::vsync(const std::shared_ptr<HWC2::Display>& display,
+ int64_t timestamp) {
+ auto displayType = HWC2::DisplayType::Invalid;
+ auto error = display->getType(&displayType);
+ if (error != HWC2::Error::None) {
+ ALOGE("vsync: Failed to determine type of display %" PRIu64,
+ display->getId());
return;
}
- queryDisplayProperties(disp);
- // Do not teardown or recreate the primary display
- if (disp != HWC_DISPLAY_PRIMARY) {
- mEventHandler.onHotplugReceived(disp, bool(connected));
- }
-}
-static float getDefaultDensity(uint32_t width, uint32_t height) {
- // Default density is based on TVs: 1080p displays get XHIGH density,
- // lower-resolution displays get TV density. Maybe eventually we'll need
- // to update it for 4K displays, though hopefully those just report
- // accurate DPI information to begin with. This is also used for virtual
- // displays and even primary displays with older hwcomposers, so be
- // careful about orientation.
-
- uint32_t h = width < height ? width : height;
- if (h >= 1080) return ACONFIGURATION_DENSITY_XHIGH;
- else return ACONFIGURATION_DENSITY_TV;
-}
-
-static const uint32_t DISPLAY_ATTRIBUTES[] = {
- HWC_DISPLAY_VSYNC_PERIOD,
- HWC_DISPLAY_WIDTH,
- HWC_DISPLAY_HEIGHT,
- HWC_DISPLAY_DPI_X,
- HWC_DISPLAY_DPI_Y,
- HWC_DISPLAY_COLOR_TRANSFORM,
- HWC_DISPLAY_NO_ATTRIBUTE,
-};
-#define NUM_DISPLAY_ATTRIBUTES (sizeof(DISPLAY_ATTRIBUTES) / sizeof(DISPLAY_ATTRIBUTES)[0])
-
-static const uint32_t PRE_HWC15_DISPLAY_ATTRIBUTES[] = {
- HWC_DISPLAY_VSYNC_PERIOD,
- HWC_DISPLAY_WIDTH,
- HWC_DISPLAY_HEIGHT,
- HWC_DISPLAY_DPI_X,
- HWC_DISPLAY_DPI_Y,
- HWC_DISPLAY_NO_ATTRIBUTE,
-};
-
-status_t HWComposer::queryDisplayProperties(int disp) {
-
- LOG_ALWAYS_FATAL_IF(!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
-
- // use zero as default value for unspecified attributes
- int32_t values[NUM_DISPLAY_ATTRIBUTES - 1];
- memset(values, 0, sizeof(values));
-
- const size_t MAX_NUM_CONFIGS = 128;
- uint32_t configs[MAX_NUM_CONFIGS] = {0};
- size_t numConfigs = MAX_NUM_CONFIGS;
- status_t err = mHwc->getDisplayConfigs(mHwc, disp, configs, &numConfigs);
- if (err != NO_ERROR) {
- // this can happen if an unpluggable display is not connected
- mDisplayData[disp].connected = false;
- return err;
+ if (displayType == HWC2::DisplayType::Virtual) {
+ ALOGE("Virtual display %" PRIu64 " passed to vsync callback",
+ display->getId());
+ return;
}
- mDisplayData[disp].currentConfig = 0;
- for (size_t c = 0; c < numConfigs; ++c) {
- err = mHwc->getDisplayAttributes(mHwc, disp, configs[c],
- DISPLAY_ATTRIBUTES, values);
- // If this is a pre-1.5 HWC, it may not know about color transform, so
- // try again with a smaller set of attributes
- if (err != NO_ERROR) {
- err = mHwc->getDisplayAttributes(mHwc, disp, configs[c],
- PRE_HWC15_DISPLAY_ATTRIBUTES, values);
- }
- if (err != NO_ERROR) {
- // we can't get this display's info. turn it off.
- mDisplayData[disp].connected = false;
- return err;
- }
-
- DisplayConfig config = DisplayConfig();
- for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) {
- switch (DISPLAY_ATTRIBUTES[i]) {
- case HWC_DISPLAY_VSYNC_PERIOD:
- config.refresh = nsecs_t(values[i]);
- break;
- case HWC_DISPLAY_WIDTH:
- config.width = values[i];
- break;
- case HWC_DISPLAY_HEIGHT:
- config.height = values[i];
- break;
- case HWC_DISPLAY_DPI_X:
- config.xdpi = values[i] / 1000.0f;
- break;
- case HWC_DISPLAY_DPI_Y:
- config.ydpi = values[i] / 1000.0f;
- break;
- case HWC_DISPLAY_COLOR_TRANSFORM:
- config.colorTransform = values[i];
- break;
- default:
- ALOG_ASSERT(false, "unknown display attribute[%zu] %#x",
- i, DISPLAY_ATTRIBUTES[i]);
- break;
- }
- }
-
- if (config.xdpi == 0.0f || config.ydpi == 0.0f) {
- float dpi = getDefaultDensity(config.width, config.height);
- config.xdpi = dpi;
- config.ydpi = dpi;
- }
-
- mDisplayData[disp].configs.push_back(config);
+ if (mHwcDisplaySlots.count(display->getId()) == 0) {
+ ALOGE("Unknown physical display %" PRIu64 " passed to vsync callback",
+ display->getId());
+ return;
}
- // FIXME: what should we set the format to?
- mDisplayData[disp].format = HAL_PIXEL_FORMAT_RGBA_8888;
- mDisplayData[disp].connected = true;
- return NO_ERROR;
-}
+ int32_t disp = mHwcDisplaySlots[display->getId()];
+ {
+ Mutex::Autolock _l(mLock);
-status_t HWComposer::setVirtualDisplayProperties(int32_t id,
- uint32_t w, uint32_t h, uint32_t format) {
- if (id < VIRTUAL_DISPLAY_ID_BASE || id >= int32_t(mNumDisplays) ||
- !mAllocatedDisplayIDs.hasBit(id)) {
- return BAD_INDEX;
+ // There have been reports of HWCs that signal several vsync events
+ // with the same timestamp when turning the display off and on. This
+ // is a bug in the HWC implementation, but filter the extra events
+ // out here so they don't cause havoc downstream.
+ if (timestamp == mLastHwVSync[disp]) {
+ ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
+ timestamp);
+ return;
+ }
+
+ mLastHwVSync[disp] = timestamp;
}
- size_t configId = mDisplayData[id].currentConfig;
- mDisplayData[id].format = format;
- DisplayConfig& config = mDisplayData[id].configs.editItemAt(configId);
- config.width = w;
- config.height = h;
- config.xdpi = config.ydpi = getDefaultDensity(w, h);
- return NO_ERROR;
+
+ char tag[16];
+ snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
+ ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
+
+ mEventHandler->onVSyncReceived(disp, timestamp);
}
-int32_t HWComposer::allocateDisplayId() {
- if (mAllocatedDisplayIDs.count() >= mNumDisplays) {
+status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
+ int32_t *outId) {
+ if (mRemainingHwcVirtualDisplays == 0) {
+ ALOGE("allocateVirtualDisplay: No remaining virtual displays");
return NO_MEMORY;
}
- int32_t id = mAllocatedDisplayIDs.firstUnmarkedBit();
- mAllocatedDisplayIDs.markBit(id);
- mDisplayData[id].connected = true;
- mDisplayData[id].configs.resize(1);
- mDisplayData[id].currentConfig = 0;
- return id;
-}
-status_t HWComposer::freeDisplayId(int32_t id) {
- if (id < NUM_BUILTIN_DISPLAYS) {
- // cannot free the reserved IDs
- return BAD_VALUE;
+ std::shared_ptr<HWC2::Display> display;
+ auto error = mHwcDevice->createVirtualDisplay(width, height, &display);
+ if (error != HWC2::Error::None) {
+ ALOGE("allocateVirtualDisplay: Failed to create HWC virtual display");
+ return NO_MEMORY;
}
- if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
- return BAD_INDEX;
+
+ size_t displaySlot = 0;
+ if (!mFreeDisplaySlots.empty()) {
+ displaySlot = *mFreeDisplaySlots.begin();
+ mFreeDisplaySlots.erase(displaySlot);
+ } else if (mDisplayData.size() < INT32_MAX) {
+ // Don't bother allocating a slot larger than we can return
+ displaySlot = mDisplayData.size();
+ mDisplayData.resize(displaySlot + 1);
+ } else {
+ ALOGE("allocateVirtualDisplay: Unable to allocate a display slot");
+ return NO_MEMORY;
}
- mAllocatedDisplayIDs.clearBit(id);
- mDisplayData[id].connected = false;
+
+ mDisplayData[displaySlot].hwcDisplay = display;
+
+ --mRemainingHwcVirtualDisplays;
+ *outId = static_cast<int32_t>(displaySlot);
+
return NO_ERROR;
}
-nsecs_t HWComposer::getRefreshTimestamp(int disp) const {
+std::shared_ptr<HWC2::Layer> HWComposer::createLayer(int32_t displayId) {
+ if (!isValidDisplay(displayId)) {
+ ALOGE("Failed to create layer on invalid display %d", displayId);
+ return nullptr;
+ }
+ auto display = mDisplayData[displayId].hwcDisplay;
+ std::shared_ptr<HWC2::Layer> layer;
+ auto error = display->createLayer(&layer);
+ if (error != HWC2::Error::None) {
+ ALOGE("Failed to create layer on display %d: %s (%d)", displayId,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ return nullptr;
+ }
+ return layer;
+}
+
+nsecs_t HWComposer::getRefreshTimestamp(int32_t disp) const {
// this returns the last refresh timestamp.
// if the last one is not available, we estimate it based on
// the refresh period and whatever closest timestamp we have.
Mutex::Autolock _l(mLock);
nsecs_t now = systemTime(CLOCK_MONOTONIC);
- size_t configId = mDisplayData[disp].currentConfig;
- return now - ((now - mLastHwVSync[disp]) %
- mDisplayData[disp].configs[configId].refresh);
+ auto vsyncPeriod = getActiveConfig(disp)->getVsyncPeriod();
+ return now - ((now - mLastHwVSync[disp]) % vsyncPeriod);
}
-sp<Fence> HWComposer::getDisplayFence(int disp) const {
- return mDisplayData[disp].lastDisplayFence;
-}
-
-uint32_t HWComposer::getFormat(int disp) const {
- if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) {
- return HAL_PIXEL_FORMAT_RGBA_8888;
- } else {
- return mDisplayData[disp].format;
- }
-}
-
-bool HWComposer::isConnected(int disp) const {
- return mDisplayData[disp].connected;
-}
-
-uint32_t HWComposer::getWidth(int disp) const {
- size_t currentConfig = mDisplayData[disp].currentConfig;
- return mDisplayData[disp].configs[currentConfig].width;
-}
-
-uint32_t HWComposer::getHeight(int disp) const {
- size_t currentConfig = mDisplayData[disp].currentConfig;
- return mDisplayData[disp].configs[currentConfig].height;
-}
-
-float HWComposer::getDpiX(int disp) const {
- size_t currentConfig = mDisplayData[disp].currentConfig;
- return mDisplayData[disp].configs[currentConfig].xdpi;
-}
-
-float HWComposer::getDpiY(int disp) const {
- size_t currentConfig = mDisplayData[disp].currentConfig;
- return mDisplayData[disp].configs[currentConfig].ydpi;
-}
-
-nsecs_t HWComposer::getRefreshPeriod(int disp) const {
- size_t currentConfig = mDisplayData[disp].currentConfig;
- return mDisplayData[disp].configs[currentConfig].refresh;
-}
-
-const Vector<HWComposer::DisplayConfig>& HWComposer::getConfigs(int disp) const {
- return mDisplayData[disp].configs;
-}
-
-size_t HWComposer::getCurrentConfig(int disp) const {
- return mDisplayData[disp].currentConfig;
-}
-
-void HWComposer::eventControl(int disp, int event, int enabled) {
- if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) {
- ALOGD("eventControl ignoring event %d on unallocated disp %d (en=%d)",
- event, disp, enabled);
- return;
- }
- if (event != EVENT_VSYNC) {
- ALOGW("eventControl got unexpected event %d (disp=%d en=%d)",
- event, disp, enabled);
- return;
- }
- status_t err = NO_ERROR;
- if (mHwc && !mDebugForceFakeVSync) {
- // NOTE: we use our own internal lock here because we have to call
- // into the HWC with the lock held, and we want to make sure
- // that even if HWC blocks (which it shouldn't), it won't
- // affect other threads.
- Mutex::Autolock _l(mEventControlLock);
- const int32_t eventBit = 1UL << event;
- const int32_t newValue = enabled ? eventBit : 0;
- const int32_t oldValue = mDisplayData[disp].events & eventBit;
- if (newValue != oldValue) {
- ATRACE_CALL();
- err = mHwc->eventControl(mHwc, disp, event, enabled);
- if (!err) {
- int32_t& events(mDisplayData[disp].events);
- events = (events & ~eventBit) | newValue;
-
- char tag[16];
- snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", disp);
- ATRACE_INT(tag, enabled);
- }
- }
- // error here should not happen -- not sure what we should
- // do if it does.
- ALOGE_IF(err, "eventControl(%d, %d) failed %s",
- event, enabled, strerror(-err));
- }
-
- if (err == NO_ERROR && mVSyncThread != NULL) {
- mVSyncThread->setEnabled(enabled);
- }
-}
-
-status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
- if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
- return BAD_INDEX;
- }
-
- if (mHwc) {
- DisplayData& disp(mDisplayData[id]);
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
- // we need space for the HWC_FRAMEBUFFER_TARGET
- numLayers++;
- }
- if (disp.capacity < numLayers || disp.list == NULL) {
- size_t size = sizeof(hwc_display_contents_1_t)
- + numLayers * sizeof(hwc_layer_1_t);
- free(disp.list);
- disp.list = (hwc_display_contents_1_t*)malloc(size);
- disp.capacity = numLayers;
- }
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
- disp.framebufferTarget = &disp.list->hwLayers[numLayers - 1];
- memset(disp.framebufferTarget, 0, sizeof(hwc_layer_1_t));
- const DisplayConfig& currentConfig =
- disp.configs[disp.currentConfig];
- const hwc_rect_t r = { 0, 0,
- (int) currentConfig.width, (int) currentConfig.height };
- disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
- disp.framebufferTarget->hints = 0;
- disp.framebufferTarget->flags = 0;
- disp.framebufferTarget->handle = disp.fbTargetHandle;
- disp.framebufferTarget->transform = 0;
- disp.framebufferTarget->blending = HWC_BLENDING_PREMULT;
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
- disp.framebufferTarget->sourceCropf.left = 0;
- disp.framebufferTarget->sourceCropf.top = 0;
- disp.framebufferTarget->sourceCropf.right =
- currentConfig.width;
- disp.framebufferTarget->sourceCropf.bottom =
- currentConfig.height;
- } else {
- disp.framebufferTarget->sourceCrop = r;
- }
- disp.framebufferTarget->displayFrame = r;
- disp.framebufferTarget->visibleRegionScreen.numRects = 1;
- disp.framebufferTarget->visibleRegionScreen.rects =
- &disp.framebufferTarget->displayFrame;
- disp.framebufferTarget->acquireFenceFd = -1;
- disp.framebufferTarget->releaseFenceFd = -1;
- disp.framebufferTarget->planeAlpha = 0xFF;
- }
- disp.list->retireFenceFd = -1;
- disp.list->flags = HWC_GEOMETRY_CHANGED;
- disp.list->numHwLayers = numLayers;
- }
- return NO_ERROR;
-}
-
-status_t HWComposer::setFramebufferTarget(int32_t id,
- const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf) {
- if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
- return BAD_INDEX;
- }
- DisplayData& disp(mDisplayData[id]);
- if (!disp.framebufferTarget) {
- // this should never happen, but apparently eglCreateWindowSurface()
- // triggers a Surface::queueBuffer() on some
- // devices (!?) -- log and ignore.
- ALOGE("HWComposer: framebufferTarget is null");
- return NO_ERROR;
- }
-
- int acquireFenceFd = -1;
- if (acquireFence->isValid()) {
- acquireFenceFd = acquireFence->dup();
- }
-
- // ALOGD("fbPost: handle=%p, fence=%d", buf->handle, acquireFenceFd);
- disp.fbTargetHandle = buf->handle;
- disp.framebufferTarget->handle = disp.fbTargetHandle;
- disp.framebufferTarget->acquireFenceFd = acquireFenceFd;
- return NO_ERROR;
-}
-
-status_t HWComposer::prepare() {
- Mutex::Autolock _l(mDisplayLock);
- for (size_t i=0 ; i<mNumDisplays ; i++) {
- DisplayData& disp(mDisplayData[i]);
- if (disp.framebufferTarget) {
- // make sure to reset the type to HWC_FRAMEBUFFER_TARGET
- // DO NOT reset the handle field to NULL, because it's possible
- // that we have nothing to redraw (eg: eglSwapBuffers() not called)
- // in which case, we should continue to use the same buffer.
- LOG_FATAL_IF(disp.list == NULL);
- disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
- }
- if (!disp.connected && disp.list != NULL) {
- ALOGW("WARNING: disp %zu: connected, non-null list, layers=%zu",
- i, disp.list->numHwLayers);
- }
- mLists[i] = disp.list;
- if (mLists[i]) {
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
- mLists[i]->outbuf = disp.outbufHandle;
- mLists[i]->outbufAcquireFenceFd = -1;
- } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
- // garbage data to catch improper use
- mLists[i]->dpy = (hwc_display_t)0xDEADBEEF;
- mLists[i]->sur = (hwc_surface_t)0xDEADBEEF;
- } else {
- mLists[i]->dpy = EGL_NO_DISPLAY;
- mLists[i]->sur = EGL_NO_SURFACE;
- }
- }
- }
-
- int err = mHwc->prepare(mHwc, mNumDisplays, mLists);
- ALOGE_IF(err, "HWComposer: prepare failed (%s)", strerror(-err));
-
- if (err == NO_ERROR) {
- // here we're just making sure that "skip" layers are set
- // to HWC_FRAMEBUFFER and we're also counting how many layers
- // we have of each type.
- //
- // If there are no window layers, we treat the display has having FB
- // composition, because SurfaceFlinger will use GLES to draw the
- // wormhole region.
- for (size_t i=0 ; i<mNumDisplays ; i++) {
- DisplayData& disp(mDisplayData[i]);
- disp.hasFbComp = false;
- disp.hasOvComp = false;
- if (disp.list) {
- for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
- hwc_layer_1_t& l = disp.list->hwLayers[i];
-
- //ALOGD("prepare: %d, type=%d, handle=%p",
- // i, l.compositionType, l.handle);
-
- if (l.flags & HWC_SKIP_LAYER) {
- l.compositionType = HWC_FRAMEBUFFER;
- }
- if (l.compositionType == HWC_FRAMEBUFFER) {
- disp.hasFbComp = true;
- }
- if (l.compositionType == HWC_OVERLAY) {
- disp.hasOvComp = true;
- }
- if (l.compositionType == HWC_CURSOR_OVERLAY) {
- disp.hasOvComp = true;
- }
- }
- if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) {
- disp.hasFbComp = true;
- }
- } else {
- disp.hasFbComp = true;
- }
- }
- }
- return (status_t)err;
-}
-
-bool HWComposer::hasHwcComposition(int32_t id) const {
- if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+bool HWComposer::isConnected(int32_t disp) const {
+ if (!isValidDisplay(disp)) {
+ ALOGE("isConnected: Attempted to access invalid display %d", disp);
return false;
- return mDisplayData[id].hasOvComp;
+ }
+ return mDisplayData[disp].hwcDisplay->isConnected();
}
-bool HWComposer::hasGlesComposition(int32_t id) const {
- if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
- return true;
- return mDisplayData[id].hasFbComp;
-}
-
-sp<Fence> HWComposer::getAndResetReleaseFence(int32_t id) {
- if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
- return Fence::NO_FENCE;
-
- int fd = INVALID_OPERATION;
- if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
- const DisplayData& disp(mDisplayData[id]);
- if (disp.framebufferTarget) {
- fd = disp.framebufferTarget->releaseFenceFd;
- disp.framebufferTarget->acquireFenceFd = -1;
- disp.framebufferTarget->releaseFenceFd = -1;
+std::vector<std::shared_ptr<const HWC2::Display::Config>>
+ HWComposer::getConfigs(int32_t displayId) const {
+ if (!isValidDisplay(displayId)) {
+ ALOGE("getConfigs: Attempted to access invalid display %d", displayId);
+ return {};
+ }
+ auto& displayData = mDisplayData[displayId];
+ auto configs = mDisplayData[displayId].hwcDisplay->getConfigs();
+ if (displayData.configMap.empty()) {
+ for (size_t i = 0; i < configs.size(); ++i) {
+ displayData.configMap[i] = configs[i];
}
}
- return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE;
+ return configs;
}
-status_t HWComposer::commit() {
- int err = NO_ERROR;
- if (mHwc) {
- if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
- // On version 1.0, the OpenGL ES target surface is communicated
- // by the (dpy, sur) fields and we are guaranteed to have only
- // a single display.
- mLists[0]->dpy = eglGetCurrentDisplay();
- mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW);
- }
-
- for (size_t i=VIRTUAL_DISPLAY_ID_BASE; i<mNumDisplays; i++) {
- DisplayData& disp(mDisplayData[i]);
- if (disp.outbufHandle) {
- mLists[i]->outbuf = disp.outbufHandle;
- mLists[i]->outbufAcquireFenceFd =
- disp.outbufAcquireFence->dup();
- }
- }
-
- err = mHwc->set(mHwc, mNumDisplays, mLists);
-
- for (size_t i=0 ; i<mNumDisplays ; i++) {
- DisplayData& disp(mDisplayData[i]);
- disp.lastDisplayFence = disp.lastRetireFence;
- disp.lastRetireFence = Fence::NO_FENCE;
- if (disp.list) {
- if (disp.list->retireFenceFd != -1) {
- disp.lastRetireFence = new Fence(disp.list->retireFenceFd);
- disp.list->retireFenceFd = -1;
- }
- disp.list->flags &= ~HWC_GEOMETRY_CHANGED;
- }
- }
+std::shared_ptr<const HWC2::Display::Config>
+ HWComposer::getActiveConfig(int32_t displayId) const {
+ if (!isValidDisplay(displayId)) {
+ ALOGE("getActiveConfigs: Attempted to access invalid display %d",
+ displayId);
+ return nullptr;
}
- return (status_t)err;
+ std::shared_ptr<const HWC2::Display::Config> config;
+ auto error = mDisplayData[displayId].hwcDisplay->getActiveConfig(&config);
+ if (error == HWC2::Error::BadConfig) {
+ ALOGV("getActiveConfig: No config active, returning null");
+ return nullptr;
+ } else if (error != HWC2::Error::None) {
+ ALOGE("getActiveConfig failed for display %d: %s (%d)", displayId,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ return nullptr;
+ } else if (!config) {
+ ALOGE("getActiveConfig returned an unknown config for display %d",
+ displayId);
+ return nullptr;
+ }
+
+ return config;
}
-status_t HWComposer::setPowerMode(int disp, int mode) {
- LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE);
- if (mHwc) {
- if (mode == HWC_POWER_MODE_OFF) {
- eventControl(disp, HWC_EVENT_VSYNC, 0);
- }
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
- return (status_t)mHwc->setPowerMode(mHwc, disp, mode);
+void HWComposer::setVsyncEnabled(int32_t disp, HWC2::Vsync enabled) {
+ if (disp < 0 || disp >= HWC_DISPLAY_VIRTUAL) {
+ ALOGD("setVsyncEnabled: Ignoring for virtual display %d", disp);
+ return;
+ }
+
+ if (!isValidDisplay(disp)) {
+ ALOGE("setVsyncEnabled: Attempted to access invalid display %d", disp);
+ return;
+ }
+
+ // NOTE: we use our own internal lock here because we have to call
+ // into the HWC with the lock held, and we want to make sure
+ // that even if HWC blocks (which it shouldn't), it won't
+ // affect other threads.
+ Mutex::Autolock _l(mVsyncLock);
+ auto& displayData = mDisplayData[disp];
+ if (enabled != displayData.vsyncEnabled) {
+ ATRACE_CALL();
+ auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
+ if (error == HWC2::Error::None) {
+ displayData.vsyncEnabled = enabled;
+
+ char tag[16];
+ snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", disp);
+ ATRACE_INT(tag, enabled == HWC2::Vsync::Enable ? 1 : 0);
} else {
- return (status_t)mHwc->blank(mHwc, disp,
- mode == HWC_POWER_MODE_OFF ? 1 : 0);
+ ALOGE("setVsyncEnabled: Failed to set vsync to %s on %d/%" PRIu64
+ ": %s (%d)", to_string(enabled).c_str(), disp,
+ mDisplayData[disp].hwcDisplay->getId(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
}
}
- return NO_ERROR;
}
-status_t HWComposer::setActiveConfig(int disp, int mode) {
- LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE);
- DisplayData& dd(mDisplayData[disp]);
- dd.currentConfig = mode;
- if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
- return (status_t)mHwc->setActiveConfig(mHwc, disp, mode);
- } else {
- LOG_FATAL_IF(mode != 0);
- }
- return NO_ERROR;
-}
-
-void HWComposer::disconnectDisplay(int disp) {
- LOG_ALWAYS_FATAL_IF(disp < 0 || disp == HWC_DISPLAY_PRIMARY);
- DisplayData& dd(mDisplayData[disp]);
- free(dd.list);
- dd.list = NULL;
- dd.framebufferTarget = NULL; // points into dd.list
- dd.fbTargetHandle = NULL;
- dd.outbufHandle = NULL;
- dd.lastRetireFence = Fence::NO_FENCE;
- dd.lastDisplayFence = Fence::NO_FENCE;
- dd.outbufAcquireFence = Fence::NO_FENCE;
- // clear all the previous configs and repopulate when a new
- // device is added
- dd.configs.clear();
-}
-
-int HWComposer::getVisualID() const {
- if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
- // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
- // is supported by the implementation. we can only be in this case
- // if we have HWC 1.1
- return HAL_PIXEL_FORMAT_RGBA_8888;
- //return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
- } else {
- return mFbDev->format;
- }
-}
-
-bool HWComposer::supportsFramebufferTarget() const {
- return (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
-}
-
-int HWComposer::fbPost(int32_t id,
- const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
- if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
- return setFramebufferTarget(id, acquireFence, buffer);
- } else {
- acquireFence->waitForever("HWComposer::fbPost");
- return mFbDev->post(mFbDev, buffer->handle);
- }
-}
-
-int HWComposer::fbCompositionComplete() {
- if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
- return NO_ERROR;
-
- if (mFbDev->compositionComplete) {
- return mFbDev->compositionComplete(mFbDev);
- } else {
- return INVALID_OPERATION;
- }
-}
-
-void HWComposer::fbDump(String8& result) {
- if (mFbDev && mFbDev->common.version >= 1 && mFbDev->dump) {
- const size_t SIZE = 4096;
- char buffer[SIZE];
- mFbDev->dump(mFbDev, buffer, SIZE);
- result.append(buffer);
- }
-}
-
-status_t HWComposer::setOutputBuffer(int32_t id, const sp<Fence>& acquireFence,
- const sp<GraphicBuffer>& buf) {
- if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+status_t HWComposer::setClientTarget(int32_t displayId,
+ const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
+ android_dataspace_t dataspace) {
+ if (!isValidDisplay(displayId)) {
return BAD_INDEX;
- if (id < VIRTUAL_DISPLAY_ID_BASE)
- return INVALID_OPERATION;
+ }
- DisplayData& disp(mDisplayData[id]);
- disp.outbufHandle = buf->handle;
- disp.outbufAcquireFence = acquireFence;
+ ALOGV("setClientTarget for display %d", displayId);
+ auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
+ buffer_handle_t handle = nullptr;
+ if ((target != nullptr) && target->getNativeBuffer()) {
+ handle = target->getNativeBuffer()->handle;
+ }
+ auto error = hwcDisplay->setClientTarget(handle, acquireFence, dataspace);
+ if (error != HWC2::Error::None) {
+ ALOGE("Failed to set client target for display %d: %s (%d)", displayId,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ return BAD_VALUE;
+ }
+
return NO_ERROR;
}
-sp<Fence> HWComposer::getLastRetireFence(int32_t id) const {
- if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+status_t HWComposer::prepare(DisplayDevice& displayDevice) {
+ ATRACE_CALL();
+
+ Mutex::Autolock _l(mDisplayLock);
+ auto displayId = displayDevice.getHwcDisplayId();
+ if (!isValidDisplay(displayId)) {
+ return BAD_INDEX;
+ }
+
+ auto& displayData = mDisplayData[displayId];
+ auto& hwcDisplay = displayData.hwcDisplay;
+ if (!hwcDisplay->isConnected()) {
+ return NO_ERROR;
+ }
+
+ uint32_t numTypes = 0;
+ uint32_t numRequests = 0;
+ auto error = hwcDisplay->validate(&numTypes, &numRequests);
+ if (error != HWC2::Error::None && error != HWC2::Error::HasChanges) {
+ ALOGE("prepare: validate failed for display %d: %s (%d)", displayId,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ return BAD_INDEX;
+ }
+
+ std::unordered_map<std::shared_ptr<HWC2::Layer>, HWC2::Composition>
+ changedTypes;
+ changedTypes.reserve(numTypes);
+ error = hwcDisplay->getChangedCompositionTypes(&changedTypes);
+ if (error != HWC2::Error::None) {
+ ALOGE("prepare: getChangedCompositionTypes failed on display %d: "
+ "%s (%d)", displayId, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ return BAD_INDEX;
+ }
+
+
+ displayData.displayRequests = static_cast<HWC2::DisplayRequest>(0);
+ std::unordered_map<std::shared_ptr<HWC2::Layer>, HWC2::LayerRequest>
+ layerRequests;
+ layerRequests.reserve(numRequests);
+ error = hwcDisplay->getRequests(&displayData.displayRequests,
+ &layerRequests);
+ if (error != HWC2::Error::None) {
+ ALOGE("prepare: getRequests failed on display %d: %s (%d)", displayId,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ return BAD_INDEX;
+ }
+
+ displayData.hasClientComposition = false;
+ displayData.hasDeviceComposition = false;
+ for (auto& layer : displayDevice.getVisibleLayersSortedByZ()) {
+ auto hwcLayer = layer->getHwcLayer(displayId);
+
+ if (changedTypes.count(hwcLayer) != 0) {
+ // We pass false so we only update our state and don't call back
+ // into the HWC device
+ validateChange(layer->getCompositionType(displayId),
+ changedTypes[hwcLayer]);
+ layer->setCompositionType(displayId, changedTypes[hwcLayer], false);
+ }
+
+ switch (layer->getCompositionType(displayId)) {
+ case HWC2::Composition::Client:
+ displayData.hasClientComposition = true;
+ break;
+ case HWC2::Composition::Device:
+ case HWC2::Composition::SolidColor:
+ case HWC2::Composition::Cursor:
+ case HWC2::Composition::Sideband:
+ displayData.hasDeviceComposition = true;
+ break;
+ default:
+ break;
+ }
+
+ if (layerRequests.count(hwcLayer) != 0 &&
+ layerRequests[hwcLayer] ==
+ HWC2::LayerRequest::ClearClientTarget) {
+ layer->setClearClientTarget(displayId, true);
+ } else {
+ if (layerRequests.count(hwcLayer) != 0) {
+ ALOGE("prepare: Unknown layer request: %s",
+ to_string(layerRequests[hwcLayer]).c_str());
+ }
+ layer->setClearClientTarget(displayId, false);
+ }
+ }
+
+ error = hwcDisplay->acceptChanges();
+ if (error != HWC2::Error::None) {
+ ALOGE("prepare: acceptChanges failed: %s", to_string(error).c_str());
+ return BAD_INDEX;
+ }
+
+ return NO_ERROR;
+}
+
+bool HWComposer::hasDeviceComposition(int32_t displayId) const {
+ if (!isValidDisplay(displayId)) {
+ ALOGE("hasDeviceComposition: Invalid display %d", displayId);
+ return false;
+ }
+ return mDisplayData[displayId].hasDeviceComposition;
+}
+
+bool HWComposer::hasClientComposition(int32_t displayId) const {
+ if (!isValidDisplay(displayId)) {
+ ALOGE("hasClientComposition: Invalid display %d", displayId);
+ return true;
+ }
+ return mDisplayData[displayId].hasClientComposition;
+}
+
+sp<Fence> HWComposer::getRetireFence(int32_t displayId) const {
+ if (!isValidDisplay(displayId)) {
+ ALOGE("getRetireFence failed for invalid display %d", displayId);
return Fence::NO_FENCE;
- return mDisplayData[id].lastRetireFence;
+ }
+ return mDisplayData[displayId].lastRetireFence;
}
-status_t HWComposer::setCursorPositionAsync(int32_t id, const Rect& pos)
-{
- if (mHwc->setCursorPositionAsync) {
- return (status_t)mHwc->setCursorPositionAsync(mHwc, id, pos.left, pos.top);
+sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId,
+ const std::shared_ptr<HWC2::Layer>& layer) const {
+ if (!isValidDisplay(displayId)) {
+ ALOGE("getLayerReleaseFence: Invalid display");
+ return Fence::NO_FENCE;
}
- else {
- return NO_ERROR;
+ auto displayFences = mDisplayData[displayId].releaseFences;
+ if (displayFences.count(layer) == 0) {
+ ALOGV("getLayerReleaseFence: Release fence not found");
+ return Fence::NO_FENCE;
}
+ return displayFences[layer];
}
-/*
- * Helper template to implement a concrete HWCLayer
- * This holds the pointer to the concrete hwc layer type
- * and implements the "iterable" side of HWCLayer.
- */
-template<typename CONCRETE, typename HWCTYPE>
-class Iterable : public HWComposer::HWCLayer {
-protected:
- HWCTYPE* const mLayerList;
- HWCTYPE* mCurrentLayer;
- Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer) { }
- inline HWCTYPE const * getLayer() const { return mCurrentLayer; }
- inline HWCTYPE* getLayer() { return mCurrentLayer; }
- virtual ~Iterable() { }
-private:
- // returns a copy of ourselves
- virtual HWComposer::HWCLayer* dup() {
- return new CONCRETE( static_cast<const CONCRETE&>(*this) );
- }
- virtual status_t setLayer(size_t index) {
- mCurrentLayer = &mLayerList[index];
- return NO_ERROR;
- }
-};
+status_t HWComposer::commit(int32_t displayId) {
+ ATRACE_CALL();
-/*
- * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0.
- * This implements the HWCLayer side of HWCIterableLayer.
- */
-class HWCLayerVersion1 : public Iterable<HWCLayerVersion1, hwc_layer_1_t> {
- struct hwc_composer_device_1* mHwc;
-public:
- HWCLayerVersion1(struct hwc_composer_device_1* hwc, hwc_layer_1_t* layer)
- : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer), mHwc(hwc) { }
-
- virtual int32_t getCompositionType() const {
- return getLayer()->compositionType;
- }
- virtual uint32_t getHints() const {
- return getLayer()->hints;
- }
- virtual sp<Fence> getAndResetReleaseFence() {
- int fd = getLayer()->releaseFenceFd;
- getLayer()->releaseFenceFd = -1;
- return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE;
- }
- virtual void setAcquireFenceFd(int fenceFd) {
- getLayer()->acquireFenceFd = fenceFd;
- }
- virtual void setPerFrameDefaultState() {
- //getLayer()->compositionType = HWC_FRAMEBUFFER;
- }
- virtual void setPlaneAlpha(uint8_t alpha) {
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
- getLayer()->planeAlpha = alpha;
- } else {
- if (alpha < 0xFF) {
- getLayer()->flags |= HWC_SKIP_LAYER;
- }
- }
- }
- virtual void setDefaultState() {
- hwc_layer_1_t* const l = getLayer();
- l->compositionType = HWC_FRAMEBUFFER;
- l->hints = 0;
- l->flags = HWC_SKIP_LAYER;
- l->handle = 0;
- l->transform = 0;
- l->blending = HWC_BLENDING_NONE;
- l->visibleRegionScreen.numRects = 0;
- l->visibleRegionScreen.rects = NULL;
- l->acquireFenceFd = -1;
- l->releaseFenceFd = -1;
- l->planeAlpha = 0xFF;
- }
- virtual void setSkip(bool skip) {
- if (skip) {
- getLayer()->flags |= HWC_SKIP_LAYER;
- } else {
- getLayer()->flags &= ~HWC_SKIP_LAYER;
- }
- }
- virtual void setIsCursorLayerHint(bool isCursor) {
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
- if (isCursor) {
- getLayer()->flags |= HWC_IS_CURSOR_LAYER;
- }
- else {
- getLayer()->flags &= ~HWC_IS_CURSOR_LAYER;
- }
- }
- }
- virtual void setBlending(uint32_t blending) {
- getLayer()->blending = blending;
- }
- virtual void setTransform(uint32_t transform) {
- getLayer()->transform = transform;
- }
- virtual void setFrame(const Rect& frame) {
- getLayer()->displayFrame = reinterpret_cast<hwc_rect_t const&>(frame);
- }
- virtual void setCrop(const FloatRect& crop) {
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
- getLayer()->sourceCropf = reinterpret_cast<hwc_frect_t const&>(crop);
- } else {
- /*
- * Since h/w composer didn't support a flot crop rect before version 1.3,
- * using integer coordinates instead produces a different output from the GL code in
- * Layer::drawWithOpenGL(). The difference can be large if the buffer crop to
- * window size ratio is large and a window crop is defined
- * (i.e.: if we scale the buffer a lot and we also crop it with a window crop).
- */
- hwc_rect_t& r = getLayer()->sourceCrop;
- r.left = int(ceilf(crop.left));
- r.top = int(ceilf(crop.top));
- r.right = int(floorf(crop.right));
- r.bottom= int(floorf(crop.bottom));
- }
- }
- virtual void setVisibleRegionScreen(const Region& reg) {
- hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen;
- mVisibleRegion = reg;
- visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(
- mVisibleRegion.getArray(&visibleRegion.numRects));
- }
- virtual void setSurfaceDamage(const Region& reg) {
- if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_5)) {
- return;
- }
- hwc_region_t& surfaceDamage = getLayer()->surfaceDamage;
- // We encode default full-screen damage as INVALID_RECT upstream, but as
- // 0 rects for HWComposer
- if (reg.isRect() && reg.getBounds() == Rect::INVALID_RECT) {
- surfaceDamage.numRects = 0;
- surfaceDamage.rects = NULL;
- return;
- }
- mSurfaceDamage = reg;
- surfaceDamage.rects = reinterpret_cast<hwc_rect_t const *>(
- mSurfaceDamage.getArray(&surfaceDamage.numRects));
- }
- virtual void setSidebandStream(const sp<NativeHandle>& stream) {
- ALOG_ASSERT(stream->handle() != NULL);
- getLayer()->compositionType = HWC_SIDEBAND;
- getLayer()->sidebandStream = stream->handle();
- }
- virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
- if (buffer == 0 || buffer->handle == 0) {
- getLayer()->compositionType = HWC_FRAMEBUFFER;
- getLayer()->flags |= HWC_SKIP_LAYER;
- getLayer()->handle = 0;
- } else {
- if (getLayer()->compositionType == HWC_SIDEBAND) {
- // If this was a sideband layer but the stream was removed, reset
- // it to FRAMEBUFFER. The HWC can change it to OVERLAY in prepare.
- getLayer()->compositionType = HWC_FRAMEBUFFER;
- }
- getLayer()->handle = buffer->handle;
- }
- }
- virtual void onDisplayed() {
- getLayer()->acquireFenceFd = -1;
+ if (!isValidDisplay(displayId)) {
+ return BAD_INDEX;
}
-protected:
- // We need to hold "copies" of these for memory management purposes. The
- // actual hwc_layer_1_t holds pointers to the memory within. Vector<>
- // internally doesn't copy the memory unless one of the copies is modified.
- Region mVisibleRegion;
- Region mSurfaceDamage;
-};
+ auto& displayData = mDisplayData[displayId];
+ auto& hwcDisplay = displayData.hwcDisplay;
+ auto error = hwcDisplay->present(&displayData.lastRetireFence);
+ if (error != HWC2::Error::None) {
+ ALOGE("commit: present failed for display %d: %s (%d)", displayId,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ return UNKNOWN_ERROR;
+ }
-/*
- * returns an iterator initialized at a given index in the layer list
- */
-HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) {
- if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
- return LayerListIterator();
+ std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>> releaseFences;
+ error = hwcDisplay->getReleaseFences(&releaseFences);
+ if (error != HWC2::Error::None) {
+ ALOGE("commit: Failed to get release fences for display %d: %s (%d)",
+ displayId, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ return UNKNOWN_ERROR;
}
- const DisplayData& disp(mDisplayData[id]);
- if (!mHwc || !disp.list || index > disp.list->numHwLayers) {
- return LayerListIterator();
- }
- return LayerListIterator(new HWCLayerVersion1(mHwc, disp.list->hwLayers), index);
+
+ displayData.releaseFences = std::move(releaseFences);
+
+ return NO_ERROR;
}
-/*
- * returns an iterator on the beginning of the layer list
- */
-HWComposer::LayerListIterator HWComposer::begin(int32_t id) {
- return getLayerIterator(id, 0);
-}
+status_t HWComposer::setPowerMode(int32_t displayId, int32_t intMode) {
+ ALOGV("setPowerMode(%d, %d)", displayId, intMode);
+ if (!isValidDisplay(displayId)) {
+ ALOGE("setPowerMode: Bad display");
+ return BAD_INDEX;
+ }
+ if (displayId >= VIRTUAL_DISPLAY_ID_BASE) {
+ ALOGE("setPowerMode: Virtual display %d passed in, returning",
+ displayId);
+ return BAD_INDEX;
+ }
-/*
- * returns an iterator on the end of the layer list
- */
-HWComposer::LayerListIterator HWComposer::end(int32_t id) {
- size_t numLayers = 0;
- if (uint32_t(id) <= 31 && mAllocatedDisplayIDs.hasBit(id)) {
- const DisplayData& disp(mDisplayData[id]);
- if (mHwc && disp.list) {
- numLayers = disp.list->numHwLayers;
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
- // with HWC 1.1, the last layer is always the HWC_FRAMEBUFFER_TARGET,
- // which we ignore when iterating through the layer list.
- ALOGE_IF(!numLayers, "mDisplayData[%d].list->numHwLayers is 0", id);
- if (numLayers) {
- numLayers--;
+ auto mode = static_cast<HWC2::PowerMode>(intMode);
+ if (mode == HWC2::PowerMode::Off) {
+ setVsyncEnabled(displayId, HWC2::Vsync::Disable);
+ }
+
+ auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
+ switch (mode) {
+ case HWC2::PowerMode::Off:
+ case HWC2::PowerMode::On:
+ ALOGV("setPowerMode: Calling HWC %s", to_string(mode).c_str());
+ {
+ auto error = hwcDisplay->setPowerMode(mode);
+ if (error != HWC2::Error::None) {
+ ALOGE("setPowerMode: Unable to set power mode %s for "
+ "display %d: %s (%d)", to_string(mode).c_str(),
+ displayId, to_string(error).c_str(),
+ static_cast<int32_t>(error));
}
}
- }
+ break;
+ case HWC2::PowerMode::Doze:
+ case HWC2::PowerMode::DozeSuspend:
+ ALOGV("setPowerMode: Calling HWC %s", to_string(mode).c_str());
+ {
+ bool supportsDoze = false;
+ auto error = hwcDisplay->supportsDoze(&supportsDoze);
+ if (error != HWC2::Error::None) {
+ ALOGE("setPowerMode: Unable to query doze support for "
+ "display %d: %s (%d)", displayId,
+ to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+ if (!supportsDoze) {
+ mode = HWC2::PowerMode::On;
+ }
+
+ error = hwcDisplay->setPowerMode(mode);
+ if (error != HWC2::Error::None) {
+ ALOGE("setPowerMode: Unable to set power mode %s for "
+ "display %d: %s (%d)", to_string(mode).c_str(),
+ displayId, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+ }
+ break;
+ default:
+ ALOGV("setPowerMode: Not calling HWC");
+ break;
}
- return getLayerIterator(id, numLayers);
+
+ return NO_ERROR;
+}
+
+status_t HWComposer::setActiveConfig(int32_t displayId, size_t configId) {
+ if (!isValidDisplay(displayId)) {
+ ALOGE("setActiveConfig: Display %d is not valid", displayId);
+ return BAD_INDEX;
+ }
+
+ auto& displayData = mDisplayData[displayId];
+ if (displayData.configMap.count(configId) == 0) {
+ ALOGE("setActiveConfig: Invalid config %zd", configId);
+ return BAD_INDEX;
+ }
+
+ auto error = displayData.hwcDisplay->setActiveConfig(
+ displayData.configMap[configId]);
+ if (error != HWC2::Error::None) {
+ ALOGE("setActiveConfig: Failed to set config %zu on display %d: "
+ "%s (%d)", configId, displayId, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+void HWComposer::disconnectDisplay(int displayId) {
+ LOG_ALWAYS_FATAL_IF(displayId < 0);
+ auto& displayData = mDisplayData[displayId];
+
+ auto displayType = HWC2::DisplayType::Invalid;
+ auto error = displayData.hwcDisplay->getType(&displayType);
+ if (error != HWC2::Error::None) {
+ ALOGE("disconnectDisplay: Failed to determine type of display %d",
+ displayId);
+ return;
+ }
+
+ // If this was a virtual display, add its slot back for reuse by future
+ // virtual displays
+ if (displayType == HWC2::DisplayType::Virtual) {
+ mFreeDisplaySlots.insert(displayId);
+ ++mRemainingHwcVirtualDisplays;
+ }
+
+ auto hwcId = displayData.hwcDisplay->getId();
+ mHwcDisplaySlots.erase(hwcId);
+ displayData.reset();
+}
+
+status_t HWComposer::setOutputBuffer(int32_t displayId,
+ const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
+ if (!isValidDisplay(displayId)) {
+ ALOGE("setOutputBuffer: Display %d is not valid", displayId);
+ return BAD_INDEX;
+ }
+
+ auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
+ auto displayType = HWC2::DisplayType::Invalid;
+ auto error = hwcDisplay->getType(&displayType);
+ if (error != HWC2::Error::None) {
+ ALOGE("setOutputBuffer: Failed to determine type of display %d",
+ displayId);
+ return NAME_NOT_FOUND;
+ }
+
+ if (displayType != HWC2::DisplayType::Virtual) {
+ ALOGE("setOutputBuffer: Display %d is not virtual", displayId);
+ return INVALID_OPERATION;
+ }
+
+ error = hwcDisplay->setOutputBuffer(buffer, acquireFence);
+ if (error != HWC2::Error::None) {
+ ALOGE("setOutputBuffer: Failed to set buffer on display %d: %s (%d)",
+ displayId, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ return UNKNOWN_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+void HWComposer::clearReleaseFences(int32_t displayId) {
+ if (!isValidDisplay(displayId)) {
+ ALOGE("clearReleaseFences: Display %d is not valid", displayId);
+ return;
+ }
+ mDisplayData[displayId].releaseFences.clear();
}
// Converts a PixelFormat to a human-readable string. Max 11 chars.
// (Could use a table of prefab String8 objects.)
+/*
static String8 getFormatStr(PixelFormat format) {
switch (format) {
case PIXEL_FORMAT_RGBA_8888: return String8("RGBA_8888");
@@ -1148,174 +754,34 @@
return result;
}
}
+*/
void HWComposer::dump(String8& result) const {
- Mutex::Autolock _l(mDisplayLock);
- if (mHwc) {
- result.appendFormat("Hardware Composer state (version %08x):\n", hwcApiVersion(mHwc));
- result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
- for (size_t i=0 ; i<mNumDisplays ; i++) {
- const DisplayData& disp(mDisplayData[i]);
- if (!disp.connected)
- continue;
-
- const Vector< sp<Layer> >& visibleLayersSortedByZ =
- mFlinger->getLayerSortedByZForHwcDisplay(i);
-
-
- result.appendFormat(" Display[%zd] configurations (* current):\n", i);
- for (size_t c = 0; c < disp.configs.size(); ++c) {
- const DisplayConfig& config(disp.configs[c]);
- result.appendFormat(" %s%zd: %ux%u, xdpi=%f, ydpi=%f"
- ", refresh=%" PRId64 ", colorTransform=%d\n",
- c == disp.currentConfig ? "* " : "", c,
- config.width, config.height, config.xdpi, config.ydpi,
- config.refresh, config.colorTransform);
- }
-
- if (disp.list) {
- result.appendFormat(
- " numHwLayers=%zu, flags=%08x\n",
- disp.list->numHwLayers, disp.list->flags);
-
- result.append(
- " type | handle | hint | flag | tr | blnd | format | source crop (l,t,r,b) | frame | name \n"
- "-----------+----------+------+------+----+------+-------------+--------------------------------+------------------------+------\n");
- // " _________ | ________ | ____ | ____ | __ | ____ | ___________ |_____._,_____._,_____._,_____._ |_____,_____,_____,_____ | ___...
- for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
- const hwc_layer_1_t&l = disp.list->hwLayers[i];
- int32_t format = -1;
- String8 name("unknown");
-
- if (i < visibleLayersSortedByZ.size()) {
- const sp<Layer>& layer(visibleLayersSortedByZ[i]);
- const sp<GraphicBuffer>& buffer(
- layer->getActiveBuffer());
- if (buffer != NULL) {
- format = buffer->getPixelFormat();
- }
- name = layer->getName();
- }
-
- int type = l.compositionType;
- if (type == HWC_FRAMEBUFFER_TARGET) {
- name = "HWC_FRAMEBUFFER_TARGET";
- format = disp.format;
- }
-
- static char const* compositionTypeName[] = {
- "GLES",
- "HWC",
- "BKGND",
- "FB TARGET",
- "SIDEBAND",
- "HWC_CURSOR",
- "UNKNOWN"};
- if (type >= NELEM(compositionTypeName))
- type = NELEM(compositionTypeName) - 1;
-
- String8 formatStr = getFormatStr(format);
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
- result.appendFormat(
- " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7.1f,%7.1f,%7.1f,%7.1f |%5d,%5d,%5d,%5d | %s\n",
- compositionTypeName[type],
- intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(),
- l.sourceCropf.left, l.sourceCropf.top, l.sourceCropf.right, l.sourceCropf.bottom,
- l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
- name.string());
- } else {
- result.appendFormat(
- " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7d,%7d,%7d,%7d |%5d,%5d,%5d,%5d | %s\n",
- compositionTypeName[type],
- intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(),
- l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
- l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
- name.string());
- }
- }
- }
- }
- }
-
- if (mHwc && mHwc->dump) {
- const size_t SIZE = 4096;
- char buffer[SIZE];
- mHwc->dump(mHwc, buffer, SIZE);
- result.append(buffer);
- }
+ // TODO: In order to provide a dump equivalent to HWC1, we need to shadow
+ // all the state going into the layers. This is probably better done in
+ // Layer itself, but it's going to take a bit of work to get there.
+ result.append(mHwcDevice->dump().c_str());
}
// ---------------------------------------------------------------------------
-HWComposer::VSyncThread::VSyncThread(HWComposer& hwc)
- : mHwc(hwc), mEnabled(false),
- mNextFakeVSync(0),
- mRefreshPeriod(hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY))
-{
-}
-
-void HWComposer::VSyncThread::setEnabled(bool enabled) {
- Mutex::Autolock _l(mLock);
- if (mEnabled != enabled) {
- mEnabled = enabled;
- mCondition.signal();
- }
-}
-
-void HWComposer::VSyncThread::onFirstRef() {
- run("VSyncThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
-}
-
-bool HWComposer::VSyncThread::threadLoop() {
- { // scope for lock
- Mutex::Autolock _l(mLock);
- while (!mEnabled) {
- mCondition.wait(mLock);
- }
- }
-
- const nsecs_t period = mRefreshPeriod;
- const nsecs_t now = systemTime(CLOCK_MONOTONIC);
- nsecs_t next_vsync = mNextFakeVSync;
- nsecs_t sleep = next_vsync - now;
- if (sleep < 0) {
- // we missed, find where the next vsync should be
- sleep = (period - ((now - next_vsync) % period));
- next_vsync = now + sleep;
- }
- mNextFakeVSync = next_vsync + period;
-
- struct timespec spec;
- spec.tv_sec = next_vsync / 1000000000;
- spec.tv_nsec = next_vsync % 1000000000;
-
- int err;
- do {
- err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
- } while (err<0 && errno == EINTR);
-
- if (err == 0) {
- mHwc.mEventHandler.onVSyncReceived(0, next_vsync);
- }
-
- return true;
-}
-
HWComposer::DisplayData::DisplayData()
-: configs(),
- currentConfig(0),
- format(HAL_PIXEL_FORMAT_RGBA_8888),
- connected(false),
- hasFbComp(false), hasOvComp(false),
- capacity(0), list(NULL),
- framebufferTarget(NULL), fbTargetHandle(0),
- lastRetireFence(Fence::NO_FENCE), lastDisplayFence(Fence::NO_FENCE),
- outbufHandle(NULL), outbufAcquireFence(Fence::NO_FENCE),
- events(0)
-{}
+ : hasClientComposition(false),
+ hasDeviceComposition(false),
+ hwcDisplay(),
+ lastRetireFence(Fence::NO_FENCE),
+ outbufHandle(nullptr),
+ outbufAcquireFence(Fence::NO_FENCE),
+ vsyncEnabled(HWC2::Vsync::Disable) {
+ ALOGV("Created new DisplayData");
+}
HWComposer::DisplayData::~DisplayData() {
- free(list);
+}
+
+void HWComposer::DisplayData::reset() {
+ ALOGV("DisplayData reset");
+ *this = DisplayData();
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 5e0b3d8..30c8f67 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -14,14 +14,18 @@
* limitations under the License.
*/
+#ifndef USE_HWC2
+#include "HWComposer_hwc1.h"
+#else
+
#ifndef ANDROID_SF_HWCOMPOSER_H
#define ANDROID_SF_HWCOMPOSER_H
+#include "HWC2.h"
+
#include <stdint.h>
#include <sys/types.h>
-#include <hardware/hwcomposer_defs.h>
-
#include <ui/Fence.h>
#include <utils/BitSet.h>
@@ -32,22 +36,29 @@
#include <utils/Timers.h>
#include <utils/Vector.h>
+#include <memory>
+#include <set>
+#include <vector>
+
extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *request,
struct timespec *remain);
-struct hwc_composer_device_1;
-struct hwc_display_contents_1;
-struct hwc_layer_1;
-struct hwc_procs;
struct framebuffer_device_t;
+namespace HWC2 {
+ class Device;
+ class Display;
+}
+
namespace android {
// ---------------------------------------------------------------------------
+class DisplayDevice;
class Fence;
class FloatRect;
class GraphicBuffer;
+class HWC2On1Adapter;
class NativeHandle;
class Region;
class String8;
@@ -58,198 +69,70 @@
public:
class EventHandler {
friend class HWComposer;
- virtual void onVSyncReceived(int disp, nsecs_t timestamp) = 0;
- virtual void onHotplugReceived(int disp, bool connected) = 0;
+ virtual void onVSyncReceived(int32_t disp, nsecs_t timestamp) = 0;
+ virtual void onHotplugReceived(int32_t disp, bool connected) = 0;
protected:
virtual ~EventHandler() {}
};
- enum {
- NUM_BUILTIN_DISPLAYS = HWC_NUM_PHYSICAL_DISPLAY_TYPES,
- MAX_HWC_DISPLAYS = HWC_NUM_DISPLAY_TYPES,
- VIRTUAL_DISPLAY_ID_BASE = HWC_DISPLAY_VIRTUAL,
- };
-
- HWComposer(
- const sp<SurfaceFlinger>& flinger,
- EventHandler& handler);
+ HWComposer(const sp<SurfaceFlinger>& flinger);
~HWComposer();
- status_t initCheck() const;
+ void setEventHandler(EventHandler* handler);
- // Returns a display ID starting at VIRTUAL_DISPLAY_ID_BASE, this ID is to
- // be used with createWorkList (and all other methods requiring an ID
- // below).
- // IDs below NUM_BUILTIN_DISPLAYS are pre-defined and therefore are
- // always valid.
- // Returns -1 if an ID cannot be allocated
- int32_t allocateDisplayId();
+ // Attempts to allocate a virtual display. If the virtual display is created
+ // on the HWC device, outId will contain its HWC ID.
+ status_t allocateVirtualDisplay(uint32_t width, uint32_t height,
+ int32_t* outId);
- // Recycles the given virtual display ID and frees the associated worklist.
- // IDs below NUM_BUILTIN_DISPLAYS are not recycled.
- status_t freeDisplayId(int32_t id);
-
+ // Attempts to create a new layer on this display
+ std::shared_ptr<HWC2::Layer> createLayer(int32_t displayId);
// Asks the HAL what it can do
- status_t prepare();
+ status_t prepare(DisplayDevice& displayDevice);
- // commits the list
- status_t commit();
+ status_t setClientTarget(int32_t displayId, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& target, android_dataspace_t dataspace);
+
+ // Finalize the layers and present them
+ status_t commit(int32_t displayId);
// set power mode
- status_t setPowerMode(int disp, int mode);
+ status_t setPowerMode(int32_t displayId, int mode);
// set active config
- status_t setActiveConfig(int disp, int mode);
+ status_t setActiveConfig(int32_t displayId, size_t configId);
// reset state when an external, non-virtual display is disconnected
- void disconnectDisplay(int disp);
-
- // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
- status_t createWorkList(int32_t id, size_t numLayers);
-
- bool supportsFramebufferTarget() const;
+ void disconnectDisplay(int32_t displayId);
// does this display have layers handled by HWC
- bool hasHwcComposition(int32_t id) const;
+ bool hasDeviceComposition(int32_t displayId) const;
// does this display have layers handled by GLES
- bool hasGlesComposition(int32_t id) const;
+ bool hasClientComposition(int32_t displayId) const;
- // get the releaseFence file descriptor for a display's framebuffer layer.
- // the release fence is only valid after commit()
- sp<Fence> getAndResetReleaseFence(int32_t id);
+ // get the retire fence for the previous frame (i.e., corresponding to the
+ // last call to presentDisplay
+ sp<Fence> getRetireFence(int32_t displayId) const;
- // needed forward declarations
- class LayerListIterator;
-
- // return the visual id to be used to find a suitable EGLConfig for
- // *ALL* displays.
- int getVisualID() const;
-
- // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface).
- int fbPost(int32_t id, const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
- int fbCompositionComplete();
- void fbDump(String8& result);
+ // Get last release fence for the given layer
+ sp<Fence> getLayerReleaseFence(int32_t displayId,
+ const std::shared_ptr<HWC2::Layer>& layer) const;
// Set the output buffer and acquire fence for a virtual display.
- // Returns INVALID_OPERATION if id is not a virtual display.
- status_t setOutputBuffer(int32_t id, const sp<Fence>& acquireFence,
+ // Returns INVALID_OPERATION if displayId is not a virtual display.
+ status_t setOutputBuffer(int32_t displayId, const sp<Fence>& acquireFence,
const sp<GraphicBuffer>& buf);
- // Get the retire fence for the last committed frame. This fence will
- // signal when the h/w composer is completely finished with the frame.
- // For physical displays, it is no longer being displayed. For virtual
- // displays, writes to the output buffer are complete.
- sp<Fence> getLastRetireFence(int32_t id) const;
-
- status_t setCursorPositionAsync(int32_t id, const Rect &pos);
-
- /*
- * Interface to hardware composer's layers functionality.
- * This abstracts the HAL interface to layers which can evolve in
- * incompatible ways from one release to another.
- * The idea is that we could extend this interface as we add
- * features to h/w composer.
- */
- class HWCLayerInterface {
- protected:
- virtual ~HWCLayerInterface() { }
- public:
- virtual int32_t getCompositionType() const = 0;
- virtual uint32_t getHints() const = 0;
- virtual sp<Fence> getAndResetReleaseFence() = 0;
- virtual void setDefaultState() = 0;
- virtual void setSkip(bool skip) = 0;
- virtual void setIsCursorLayerHint(bool isCursor = true) = 0;
- virtual void setBlending(uint32_t blending) = 0;
- virtual void setTransform(uint32_t transform) = 0;
- virtual void setFrame(const Rect& frame) = 0;
- virtual void setCrop(const FloatRect& crop) = 0;
- virtual void setVisibleRegionScreen(const Region& reg) = 0;
- virtual void setSurfaceDamage(const Region& reg) = 0;
- virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0;
- virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
- virtual void setAcquireFenceFd(int fenceFd) = 0;
- virtual void setPlaneAlpha(uint8_t alpha) = 0;
- virtual void onDisplayed() = 0;
- };
-
- /*
- * Interface used to implement an iterator to a list
- * of HWCLayer.
- */
- class HWCLayer : public HWCLayerInterface {
- friend class LayerListIterator;
- // select the layer at the given index
- virtual status_t setLayer(size_t index) = 0;
- virtual HWCLayer* dup() = 0;
- static HWCLayer* copy(HWCLayer *rhs) {
- return rhs ? rhs->dup() : NULL;
- }
- protected:
- virtual ~HWCLayer() { }
- };
-
- /*
- * Iterator through a HWCLayer list.
- * This behaves more or less like a forward iterator.
- */
- class LayerListIterator {
- friend class HWComposer;
- HWCLayer* const mLayerList;
- size_t mIndex;
-
- LayerListIterator() : mLayerList(NULL), mIndex(0) { }
-
- LayerListIterator(HWCLayer* layer, size_t index)
- : mLayerList(layer), mIndex(index) { }
-
- // we don't allow assignment, because we don't need it for now
- LayerListIterator& operator = (const LayerListIterator& rhs);
-
- public:
- // copy operators
- LayerListIterator(const LayerListIterator& rhs)
- : mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) {
- }
-
- ~LayerListIterator() { delete mLayerList; }
-
- // pre-increment
- LayerListIterator& operator++() {
- mLayerList->setLayer(++mIndex);
- return *this;
- }
-
- // dereference
- HWCLayerInterface& operator * () { return *mLayerList; }
- HWCLayerInterface* operator -> () { return mLayerList; }
-
- // comparison
- bool operator == (const LayerListIterator& rhs) const {
- return mIndex == rhs.mIndex;
- }
- bool operator != (const LayerListIterator& rhs) const {
- return !operator==(rhs);
- }
- };
-
- // Returns an iterator to the beginning of the layer list
- LayerListIterator begin(int32_t id);
-
- // Returns an iterator to the end of the layer list
- LayerListIterator end(int32_t id);
-
+ // After SurfaceFlinger has retrieved the release fences for all the frames,
+ // it can call this to clear the shared pointers in the release fence map
+ void clearReleaseFences(int32_t displayId);
// Events handling ---------------------------------------------------------
- enum {
- EVENT_VSYNC = HWC_EVENT_VSYNC
- };
-
- void eventControl(int disp, int event, int enabled);
+ void setVsyncEnabled(int32_t disp, HWC2::Vsync enabled);
struct DisplayConfig {
uint32_t width;
@@ -262,119 +145,81 @@
// Query display parameters. Pass in a display index (e.g.
// HWC_DISPLAY_PRIMARY).
- nsecs_t getRefreshTimestamp(int disp) const;
- sp<Fence> getDisplayFence(int disp) const;
- uint32_t getFormat(int disp) const;
- bool isConnected(int disp) const;
+ nsecs_t getRefreshTimestamp(int32_t disp) const;
+ bool isConnected(int32_t disp) const;
- // These return the values for the current config of a given display index.
- // To get the values for all configs, use getConfigs below.
- uint32_t getWidth(int disp) const;
- uint32_t getHeight(int disp) const;
- float getDpiX(int disp) const;
- float getDpiY(int disp) const;
- nsecs_t getRefreshPeriod(int disp) const;
+ // Non-const because it can update configMap inside of mDisplayData
+ std::vector<std::shared_ptr<const HWC2::Display::Config>>
+ getConfigs(int32_t displayId) const;
- const Vector<DisplayConfig>& getConfigs(int disp) const;
- size_t getCurrentConfig(int disp) const;
-
- status_t setVirtualDisplayProperties(int32_t id, uint32_t w, uint32_t h,
- uint32_t format);
-
- // this class is only used to fake the VSync event on systems that don't
- // have it.
- class VSyncThread : public Thread {
- HWComposer& mHwc;
- mutable Mutex mLock;
- Condition mCondition;
- bool mEnabled;
- mutable nsecs_t mNextFakeVSync;
- nsecs_t mRefreshPeriod;
- virtual void onFirstRef();
- virtual bool threadLoop();
- public:
- VSyncThread(HWComposer& hwc);
- void setEnabled(bool enabled);
- };
-
- friend class VSyncThread;
+ std::shared_ptr<const HWC2::Display::Config>
+ getActiveConfig(int32_t displayId) const;
// for debugging ----------------------------------------------------------
void dump(String8& out) const;
private:
- void loadHwcModule();
- int loadFbHalModule();
+ static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2;
- LayerListIterator getLayerIterator(int32_t id, size_t index);
+ void loadHwcModule();
+
+ bool isValidDisplay(int32_t displayId) const;
+ static void validateChange(HWC2::Composition from, HWC2::Composition to);
struct cb_context;
- static void hook_invalidate(const struct hwc_procs* procs);
- static void hook_vsync(const struct hwc_procs* procs, int disp,
+ void invalidate(const std::shared_ptr<HWC2::Display>& display);
+ void vsync(const std::shared_ptr<HWC2::Display>& display,
int64_t timestamp);
- static void hook_hotplug(const struct hwc_procs* procs, int disp,
- int connected);
-
- inline void invalidate();
- inline void vsync(int disp, int64_t timestamp);
- inline void hotplug(int disp, int connected);
-
- status_t queryDisplayProperties(int disp);
-
- status_t setFramebufferTarget(int32_t id,
- const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
+ void hotplug(const std::shared_ptr<HWC2::Display>& display,
+ HWC2::Connection connected);
struct DisplayData {
DisplayData();
~DisplayData();
- Vector<DisplayConfig> configs;
- size_t currentConfig;
- uint32_t format; // pixel format from FB hal, for pre-hwc-1.1
- bool connected;
- bool hasFbComp;
- bool hasOvComp;
- size_t capacity;
- hwc_display_contents_1* list;
- hwc_layer_1* framebufferTarget;
- buffer_handle_t fbTargetHandle;
+ void reset();
+
+ bool hasClientComposition;
+ bool hasDeviceComposition;
+ std::shared_ptr<HWC2::Display> hwcDisplay;
+ HWC2::DisplayRequest displayRequests;
sp<Fence> lastRetireFence; // signals when the last set op retires
- sp<Fence> lastDisplayFence; // signals when the last set op takes
- // effect on screen
+ std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>>
+ releaseFences;
buffer_handle_t outbufHandle;
sp<Fence> outbufAcquireFence;
+ mutable std::unordered_map<int32_t,
+ std::shared_ptr<const HWC2::Display::Config>> configMap;
- // protected by mEventControlLock
- int32_t events;
+ // protected by mVsyncLock
+ HWC2::Vsync vsyncEnabled;
};
sp<SurfaceFlinger> mFlinger;
- framebuffer_device_t* mFbDev;
- struct hwc_composer_device_1* mHwc;
- // invariant: mLists[0] != NULL iff mHwc != NULL
- // mLists[i>0] can be NULL. that display is to be ignored
- struct hwc_display_contents_1* mLists[MAX_HWC_DISPLAYS];
- DisplayData mDisplayData[MAX_HWC_DISPLAYS];
+ std::unique_ptr<HWC2On1Adapter> mAdapter;
+ std::unique_ptr<HWC2::Device> mHwcDevice;
+ std::vector<DisplayData> mDisplayData;
+ std::set<size_t> mFreeDisplaySlots;
+ std::unordered_map<hwc2_display_t, int32_t> mHwcDisplaySlots;
// protect mDisplayData from races between prepare and dump
mutable Mutex mDisplayLock;
- size_t mNumDisplays;
cb_context* mCBContext;
- EventHandler& mEventHandler;
+ EventHandler* mEventHandler;
size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
- sp<VSyncThread> mVSyncThread;
- bool mDebugForceFakeVSync;
- BitSet32 mAllocatedDisplayIDs;
+ uint32_t mRemainingHwcVirtualDisplays;
// protected by mLock
mutable Mutex mLock;
- mutable nsecs_t mLastHwVSync[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
+ mutable std::unordered_map<int32_t, nsecs_t> mLastHwVSync;
// thread-safe
- mutable Mutex mEventControlLock;
+ mutable Mutex mVsyncLock;
};
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_SF_HWCOMPOSER_H
+
+#endif // #ifdef USE_HWC2
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
new file mode 100644
index 0000000..d37fcb2
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
@@ -0,0 +1,1322 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <inttypes.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/misc.h>
+#include <utils/NativeHandle.h>
+#include <utils/String8.h>
+#include <utils/Thread.h>
+#include <utils/Trace.h>
+#include <utils/Vector.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+
+#include <android/configuration.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "HWComposer.h"
+
+#include "../Layer.h" // needed only for debugging
+#include "../SurfaceFlinger.h"
+
+namespace android {
+
+#define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION
+
+static uint32_t hwcApiVersion(const hwc_composer_device_1_t* hwc) {
+ uint32_t hwcVersion = hwc->common.version;
+ return hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
+}
+
+static uint32_t hwcHeaderVersion(const hwc_composer_device_1_t* hwc) {
+ uint32_t hwcVersion = hwc->common.version;
+ return hwcVersion & HARDWARE_API_VERSION_2_HEADER_MASK;
+}
+
+static bool hwcHasApiVersion(const hwc_composer_device_1_t* hwc,
+ uint32_t version) {
+ return hwcApiVersion(hwc) >= (version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK);
+}
+
+// ---------------------------------------------------------------------------
+
+struct HWComposer::cb_context {
+ struct callbacks : public hwc_procs_t {
+ // these are here to facilitate the transition when adding
+ // new callbacks (an implementation can check for NULL before
+ // calling a new callback).
+ void (*zero[4])(void);
+ };
+ callbacks procs;
+ HWComposer* hwc;
+};
+
+// ---------------------------------------------------------------------------
+
+HWComposer::HWComposer(
+ const sp<SurfaceFlinger>& flinger,
+ EventHandler& handler)
+ : mFlinger(flinger),
+ mFbDev(0), mHwc(0), mNumDisplays(1),
+ mCBContext(new cb_context),
+ mEventHandler(handler),
+ mDebugForceFakeVSync(false)
+{
+ for (size_t i =0 ; i<MAX_HWC_DISPLAYS ; i++) {
+ mLists[i] = 0;
+ }
+
+ for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) {
+ mLastHwVSync[i] = 0;
+ mVSyncCounts[i] = 0;
+ }
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.no_hw_vsync", value, "0");
+ mDebugForceFakeVSync = atoi(value);
+
+ bool needVSyncThread = true;
+
+ // Note: some devices may insist that the FB HAL be opened before HWC.
+ int fberr = loadFbHalModule();
+ loadHwcModule();
+
+ if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // close FB HAL if we don't needed it.
+ // FIXME: this is temporary until we're not forced to open FB HAL
+ // before HWC.
+ framebuffer_close(mFbDev);
+ mFbDev = NULL;
+ }
+
+ // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory.
+ if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
+ && !mFbDev) {
+ ALOGE("ERROR: failed to open framebuffer (%s), aborting",
+ strerror(-fberr));
+ abort();
+ }
+
+ // these display IDs are always reserved
+ for (size_t i=0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {
+ mAllocatedDisplayIDs.markBit(i);
+ }
+
+ if (mHwc) {
+ ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
+ (hwcApiVersion(mHwc) >> 24) & 0xff,
+ (hwcApiVersion(mHwc) >> 16) & 0xff);
+ if (mHwc->registerProcs) {
+ mCBContext->hwc = this;
+ mCBContext->procs.invalidate = &hook_invalidate;
+ mCBContext->procs.vsync = &hook_vsync;
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
+ mCBContext->procs.hotplug = &hook_hotplug;
+ else
+ mCBContext->procs.hotplug = NULL;
+ memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
+ mHwc->registerProcs(mHwc, &mCBContext->procs);
+ }
+
+ // don't need a vsync thread if we have a hardware composer
+ needVSyncThread = false;
+ // always turn vsync off when we start
+ eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
+
+ // the number of displays we actually have depends on the
+ // hw composer version
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+ // 1.3 adds support for virtual displays
+ mNumDisplays = MAX_HWC_DISPLAYS;
+ } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // 1.1 adds support for multiple displays
+ mNumDisplays = NUM_BUILTIN_DISPLAYS;
+ } else {
+ mNumDisplays = 1;
+ }
+ }
+
+ if (mFbDev) {
+ ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)),
+ "should only have fbdev if no hwc or hwc is 1.0");
+
+ DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
+ disp.connected = true;
+ disp.format = mFbDev->format;
+ DisplayConfig config = DisplayConfig();
+ config.width = mFbDev->width;
+ config.height = mFbDev->height;
+ config.xdpi = mFbDev->xdpi;
+ config.ydpi = mFbDev->ydpi;
+ config.refresh = nsecs_t(1e9 / mFbDev->fps);
+ disp.configs.push_back(config);
+ disp.currentConfig = 0;
+ } else if (mHwc) {
+ // here we're guaranteed to have at least HWC 1.1
+ for (size_t i =0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {
+ queryDisplayProperties(i);
+ }
+ }
+
+ if (needVSyncThread) {
+ // we don't have VSYNC support, we need to fake it
+ mVSyncThread = new VSyncThread(*this);
+ }
+}
+
+HWComposer::~HWComposer() {
+ if (mHwc) {
+ eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
+ }
+ if (mVSyncThread != NULL) {
+ mVSyncThread->requestExitAndWait();
+ }
+ if (mHwc) {
+ hwc_close_1(mHwc);
+ }
+ if (mFbDev) {
+ framebuffer_close(mFbDev);
+ }
+ delete mCBContext;
+}
+
+// Load and prepare the hardware composer module. Sets mHwc.
+void HWComposer::loadHwcModule()
+{
+ hw_module_t const* module;
+
+ if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
+ ALOGE("%s module not found", HWC_HARDWARE_MODULE_ID);
+ return;
+ }
+
+ int err = hwc_open_1(module, &mHwc);
+ if (err) {
+ ALOGE("%s device failed to initialize (%s)",
+ HWC_HARDWARE_COMPOSER, strerror(-err));
+ return;
+ }
+
+ if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) ||
+ hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION ||
+ hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) {
+ ALOGE("%s device version %#x unsupported, will not be used",
+ HWC_HARDWARE_COMPOSER, mHwc->common.version);
+ hwc_close_1(mHwc);
+ mHwc = NULL;
+ return;
+ }
+}
+
+// Load and prepare the FB HAL, which uses the gralloc module. Sets mFbDev.
+int HWComposer::loadFbHalModule()
+{
+ hw_module_t const* module;
+
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ if (err != 0) {
+ ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID);
+ return err;
+ }
+
+ return framebuffer_open(module, &mFbDev);
+}
+
+status_t HWComposer::initCheck() const {
+ return mHwc ? NO_ERROR : NO_INIT;
+}
+
+void HWComposer::hook_invalidate(const struct hwc_procs* procs) {
+ cb_context* ctx = reinterpret_cast<cb_context*>(
+ const_cast<hwc_procs_t*>(procs));
+ ctx->hwc->invalidate();
+}
+
+void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp,
+ int64_t timestamp) {
+ cb_context* ctx = reinterpret_cast<cb_context*>(
+ const_cast<hwc_procs_t*>(procs));
+ ctx->hwc->vsync(disp, timestamp);
+}
+
+void HWComposer::hook_hotplug(const struct hwc_procs* procs, int disp,
+ int connected) {
+ cb_context* ctx = reinterpret_cast<cb_context*>(
+ const_cast<hwc_procs_t*>(procs));
+ ctx->hwc->hotplug(disp, connected);
+}
+
+void HWComposer::invalidate() {
+ mFlinger->repaintEverything();
+}
+
+void HWComposer::vsync(int disp, int64_t timestamp) {
+ if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+ {
+ Mutex::Autolock _l(mLock);
+
+ // There have been reports of HWCs that signal several vsync events
+ // with the same timestamp when turning the display off and on. This
+ // is a bug in the HWC implementation, but filter the extra events
+ // out here so they don't cause havoc downstream.
+ if (timestamp == mLastHwVSync[disp]) {
+ ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
+ timestamp);
+ return;
+ }
+
+ mLastHwVSync[disp] = timestamp;
+ }
+
+ char tag[16];
+ snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
+ ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
+
+ mEventHandler.onVSyncReceived(disp, timestamp);
+ }
+}
+
+void HWComposer::hotplug(int disp, int connected) {
+ if (disp >= VIRTUAL_DISPLAY_ID_BASE) {
+ ALOGE("hotplug event received for invalid display: disp=%d connected=%d",
+ disp, connected);
+ return;
+ }
+ queryDisplayProperties(disp);
+ // Do not teardown or recreate the primary display
+ if (disp != HWC_DISPLAY_PRIMARY) {
+ mEventHandler.onHotplugReceived(disp, bool(connected));
+ }
+}
+
+static float getDefaultDensity(uint32_t width, uint32_t height) {
+ // Default density is based on TVs: 1080p displays get XHIGH density,
+ // lower-resolution displays get TV density. Maybe eventually we'll need
+ // to update it for 4K displays, though hopefully those just report
+ // accurate DPI information to begin with. This is also used for virtual
+ // displays and even primary displays with older hwcomposers, so be
+ // careful about orientation.
+
+ uint32_t h = width < height ? width : height;
+ if (h >= 1080) return ACONFIGURATION_DENSITY_XHIGH;
+ else return ACONFIGURATION_DENSITY_TV;
+}
+
+static const uint32_t DISPLAY_ATTRIBUTES[] = {
+ HWC_DISPLAY_VSYNC_PERIOD,
+ HWC_DISPLAY_WIDTH,
+ HWC_DISPLAY_HEIGHT,
+ HWC_DISPLAY_DPI_X,
+ HWC_DISPLAY_DPI_Y,
+ HWC_DISPLAY_COLOR_TRANSFORM,
+ HWC_DISPLAY_NO_ATTRIBUTE,
+};
+#define NUM_DISPLAY_ATTRIBUTES (sizeof(DISPLAY_ATTRIBUTES) / sizeof(DISPLAY_ATTRIBUTES)[0])
+
+static const uint32_t PRE_HWC15_DISPLAY_ATTRIBUTES[] = {
+ HWC_DISPLAY_VSYNC_PERIOD,
+ HWC_DISPLAY_WIDTH,
+ HWC_DISPLAY_HEIGHT,
+ HWC_DISPLAY_DPI_X,
+ HWC_DISPLAY_DPI_Y,
+ HWC_DISPLAY_NO_ATTRIBUTE,
+};
+
+status_t HWComposer::queryDisplayProperties(int disp) {
+
+ LOG_ALWAYS_FATAL_IF(!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
+
+ // use zero as default value for unspecified attributes
+ int32_t values[NUM_DISPLAY_ATTRIBUTES - 1];
+ memset(values, 0, sizeof(values));
+
+ const size_t MAX_NUM_CONFIGS = 128;
+ uint32_t configs[MAX_NUM_CONFIGS] = {0};
+ size_t numConfigs = MAX_NUM_CONFIGS;
+ status_t err = mHwc->getDisplayConfigs(mHwc, disp, configs, &numConfigs);
+ if (err != NO_ERROR) {
+ // this can happen if an unpluggable display is not connected
+ mDisplayData[disp].connected = false;
+ return err;
+ }
+
+ mDisplayData[disp].currentConfig = 0;
+ for (size_t c = 0; c < numConfigs; ++c) {
+ err = mHwc->getDisplayAttributes(mHwc, disp, configs[c],
+ DISPLAY_ATTRIBUTES, values);
+ // If this is a pre-1.5 HWC, it may not know about color transform, so
+ // try again with a smaller set of attributes
+ if (err != NO_ERROR) {
+ err = mHwc->getDisplayAttributes(mHwc, disp, configs[c],
+ PRE_HWC15_DISPLAY_ATTRIBUTES, values);
+ }
+ if (err != NO_ERROR) {
+ // we can't get this display's info. turn it off.
+ mDisplayData[disp].connected = false;
+ return err;
+ }
+
+ DisplayConfig config = DisplayConfig();
+ for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) {
+ switch (DISPLAY_ATTRIBUTES[i]) {
+ case HWC_DISPLAY_VSYNC_PERIOD:
+ config.refresh = nsecs_t(values[i]);
+ break;
+ case HWC_DISPLAY_WIDTH:
+ config.width = values[i];
+ break;
+ case HWC_DISPLAY_HEIGHT:
+ config.height = values[i];
+ break;
+ case HWC_DISPLAY_DPI_X:
+ config.xdpi = values[i] / 1000.0f;
+ break;
+ case HWC_DISPLAY_DPI_Y:
+ config.ydpi = values[i] / 1000.0f;
+ break;
+ case HWC_DISPLAY_COLOR_TRANSFORM:
+ config.colorTransform = values[i];
+ break;
+ default:
+ ALOG_ASSERT(false, "unknown display attribute[%zu] %#x",
+ i, DISPLAY_ATTRIBUTES[i]);
+ break;
+ }
+ }
+
+ if (config.xdpi == 0.0f || config.ydpi == 0.0f) {
+ float dpi = getDefaultDensity(config.width, config.height);
+ config.xdpi = dpi;
+ config.ydpi = dpi;
+ }
+
+ mDisplayData[disp].configs.push_back(config);
+ }
+
+ // FIXME: what should we set the format to?
+ mDisplayData[disp].format = HAL_PIXEL_FORMAT_RGBA_8888;
+ mDisplayData[disp].connected = true;
+ return NO_ERROR;
+}
+
+status_t HWComposer::setVirtualDisplayProperties(int32_t id,
+ uint32_t w, uint32_t h, uint32_t format) {
+ if (id < VIRTUAL_DISPLAY_ID_BASE || id >= int32_t(mNumDisplays) ||
+ !mAllocatedDisplayIDs.hasBit(id)) {
+ return BAD_INDEX;
+ }
+ size_t configId = mDisplayData[id].currentConfig;
+ mDisplayData[id].format = format;
+ DisplayConfig& config = mDisplayData[id].configs.editItemAt(configId);
+ config.width = w;
+ config.height = h;
+ config.xdpi = config.ydpi = getDefaultDensity(w, h);
+ return NO_ERROR;
+}
+
+int32_t HWComposer::allocateDisplayId() {
+ if (mAllocatedDisplayIDs.count() >= mNumDisplays) {
+ return NO_MEMORY;
+ }
+ int32_t id = mAllocatedDisplayIDs.firstUnmarkedBit();
+ mAllocatedDisplayIDs.markBit(id);
+ mDisplayData[id].connected = true;
+ mDisplayData[id].configs.resize(1);
+ mDisplayData[id].currentConfig = 0;
+ return id;
+}
+
+status_t HWComposer::freeDisplayId(int32_t id) {
+ if (id < NUM_BUILTIN_DISPLAYS) {
+ // cannot free the reserved IDs
+ return BAD_VALUE;
+ }
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+ return BAD_INDEX;
+ }
+ mAllocatedDisplayIDs.clearBit(id);
+ mDisplayData[id].connected = false;
+ return NO_ERROR;
+}
+
+nsecs_t HWComposer::getRefreshTimestamp(int disp) const {
+ // this returns the last refresh timestamp.
+ // if the last one is not available, we estimate it based on
+ // the refresh period and whatever closest timestamp we have.
+ Mutex::Autolock _l(mLock);
+ nsecs_t now = systemTime(CLOCK_MONOTONIC);
+ size_t configId = mDisplayData[disp].currentConfig;
+ return now - ((now - mLastHwVSync[disp]) %
+ mDisplayData[disp].configs[configId].refresh);
+}
+
+sp<Fence> HWComposer::getDisplayFence(int disp) const {
+ return mDisplayData[disp].lastDisplayFence;
+}
+
+uint32_t HWComposer::getFormat(int disp) const {
+ if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) {
+ return HAL_PIXEL_FORMAT_RGBA_8888;
+ } else {
+ return mDisplayData[disp].format;
+ }
+}
+
+bool HWComposer::isConnected(int disp) const {
+ return mDisplayData[disp].connected;
+}
+
+uint32_t HWComposer::getWidth(int disp) const {
+ size_t currentConfig = mDisplayData[disp].currentConfig;
+ return mDisplayData[disp].configs[currentConfig].width;
+}
+
+uint32_t HWComposer::getHeight(int disp) const {
+ size_t currentConfig = mDisplayData[disp].currentConfig;
+ return mDisplayData[disp].configs[currentConfig].height;
+}
+
+float HWComposer::getDpiX(int disp) const {
+ size_t currentConfig = mDisplayData[disp].currentConfig;
+ return mDisplayData[disp].configs[currentConfig].xdpi;
+}
+
+float HWComposer::getDpiY(int disp) const {
+ size_t currentConfig = mDisplayData[disp].currentConfig;
+ return mDisplayData[disp].configs[currentConfig].ydpi;
+}
+
+nsecs_t HWComposer::getRefreshPeriod(int disp) const {
+ size_t currentConfig = mDisplayData[disp].currentConfig;
+ return mDisplayData[disp].configs[currentConfig].refresh;
+}
+
+const Vector<HWComposer::DisplayConfig>& HWComposer::getConfigs(int disp) const {
+ return mDisplayData[disp].configs;
+}
+
+size_t HWComposer::getCurrentConfig(int disp) const {
+ return mDisplayData[disp].currentConfig;
+}
+
+void HWComposer::eventControl(int disp, int event, int enabled) {
+ if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) {
+ ALOGD("eventControl ignoring event %d on unallocated disp %d (en=%d)",
+ event, disp, enabled);
+ return;
+ }
+ if (event != EVENT_VSYNC) {
+ ALOGW("eventControl got unexpected event %d (disp=%d en=%d)",
+ event, disp, enabled);
+ return;
+ }
+ status_t err = NO_ERROR;
+ if (mHwc && !mDebugForceFakeVSync) {
+ // NOTE: we use our own internal lock here because we have to call
+ // into the HWC with the lock held, and we want to make sure
+ // that even if HWC blocks (which it shouldn't), it won't
+ // affect other threads.
+ Mutex::Autolock _l(mEventControlLock);
+ const int32_t eventBit = 1UL << event;
+ const int32_t newValue = enabled ? eventBit : 0;
+ const int32_t oldValue = mDisplayData[disp].events & eventBit;
+ if (newValue != oldValue) {
+ ATRACE_CALL();
+ err = mHwc->eventControl(mHwc, disp, event, enabled);
+ if (!err) {
+ int32_t& events(mDisplayData[disp].events);
+ events = (events & ~eventBit) | newValue;
+
+ char tag[16];
+ snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", disp);
+ ATRACE_INT(tag, enabled);
+ }
+ }
+ // error here should not happen -- not sure what we should
+ // do if it does.
+ ALOGE_IF(err, "eventControl(%d, %d) failed %s",
+ event, enabled, strerror(-err));
+ }
+
+ if (err == NO_ERROR && mVSyncThread != NULL) {
+ mVSyncThread->setEnabled(enabled);
+ }
+}
+
+status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+ return BAD_INDEX;
+ }
+
+ if (mHwc) {
+ DisplayData& disp(mDisplayData[id]);
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // we need space for the HWC_FRAMEBUFFER_TARGET
+ numLayers++;
+ }
+ if (disp.capacity < numLayers || disp.list == NULL) {
+ size_t size = sizeof(hwc_display_contents_1_t)
+ + numLayers * sizeof(hwc_layer_1_t);
+ free(disp.list);
+ disp.list = (hwc_display_contents_1_t*)malloc(size);
+ disp.capacity = numLayers;
+ }
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ disp.framebufferTarget = &disp.list->hwLayers[numLayers - 1];
+ memset(disp.framebufferTarget, 0, sizeof(hwc_layer_1_t));
+ const DisplayConfig& currentConfig =
+ disp.configs[disp.currentConfig];
+ const hwc_rect_t r = { 0, 0,
+ (int) currentConfig.width, (int) currentConfig.height };
+ disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
+ disp.framebufferTarget->hints = 0;
+ disp.framebufferTarget->flags = 0;
+ disp.framebufferTarget->handle = disp.fbTargetHandle;
+ disp.framebufferTarget->transform = 0;
+ disp.framebufferTarget->blending = HWC_BLENDING_PREMULT;
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+ disp.framebufferTarget->sourceCropf.left = 0;
+ disp.framebufferTarget->sourceCropf.top = 0;
+ disp.framebufferTarget->sourceCropf.right =
+ currentConfig.width;
+ disp.framebufferTarget->sourceCropf.bottom =
+ currentConfig.height;
+ } else {
+ disp.framebufferTarget->sourceCrop = r;
+ }
+ disp.framebufferTarget->displayFrame = r;
+ disp.framebufferTarget->visibleRegionScreen.numRects = 1;
+ disp.framebufferTarget->visibleRegionScreen.rects =
+ &disp.framebufferTarget->displayFrame;
+ disp.framebufferTarget->acquireFenceFd = -1;
+ disp.framebufferTarget->releaseFenceFd = -1;
+ disp.framebufferTarget->planeAlpha = 0xFF;
+ }
+ disp.list->retireFenceFd = -1;
+ disp.list->flags = HWC_GEOMETRY_CHANGED;
+ disp.list->numHwLayers = numLayers;
+ }
+ return NO_ERROR;
+}
+
+status_t HWComposer::setFramebufferTarget(int32_t id,
+ const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf) {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+ return BAD_INDEX;
+ }
+ DisplayData& disp(mDisplayData[id]);
+ if (!disp.framebufferTarget) {
+ // this should never happen, but apparently eglCreateWindowSurface()
+ // triggers a Surface::queueBuffer() on some
+ // devices (!?) -- log and ignore.
+ ALOGE("HWComposer: framebufferTarget is null");
+ return NO_ERROR;
+ }
+
+ int acquireFenceFd = -1;
+ if (acquireFence->isValid()) {
+ acquireFenceFd = acquireFence->dup();
+ }
+
+ // ALOGD("fbPost: handle=%p, fence=%d", buf->handle, acquireFenceFd);
+ disp.fbTargetHandle = buf->handle;
+ disp.framebufferTarget->handle = disp.fbTargetHandle;
+ disp.framebufferTarget->acquireFenceFd = acquireFenceFd;
+ return NO_ERROR;
+}
+
+status_t HWComposer::prepare() {
+ Mutex::Autolock _l(mDisplayLock);
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ DisplayData& disp(mDisplayData[i]);
+ if (disp.framebufferTarget) {
+ // make sure to reset the type to HWC_FRAMEBUFFER_TARGET
+ // DO NOT reset the handle field to NULL, because it's possible
+ // that we have nothing to redraw (eg: eglSwapBuffers() not called)
+ // in which case, we should continue to use the same buffer.
+ LOG_FATAL_IF(disp.list == NULL);
+ disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
+ }
+ if (!disp.connected && disp.list != NULL) {
+ ALOGW("WARNING: disp %zu: connected, non-null list, layers=%zu",
+ i, disp.list->numHwLayers);
+ }
+ mLists[i] = disp.list;
+ if (mLists[i]) {
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+ mLists[i]->outbuf = disp.outbufHandle;
+ mLists[i]->outbufAcquireFenceFd = -1;
+ } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // garbage data to catch improper use
+ mLists[i]->dpy = (hwc_display_t)0xDEADBEEF;
+ mLists[i]->sur = (hwc_surface_t)0xDEADBEEF;
+ } else {
+ mLists[i]->dpy = EGL_NO_DISPLAY;
+ mLists[i]->sur = EGL_NO_SURFACE;
+ }
+ }
+ }
+
+ int err = mHwc->prepare(mHwc, mNumDisplays, mLists);
+ ALOGE_IF(err, "HWComposer: prepare failed (%s)", strerror(-err));
+
+ if (err == NO_ERROR) {
+ // here we're just making sure that "skip" layers are set
+ // to HWC_FRAMEBUFFER and we're also counting how many layers
+ // we have of each type.
+ //
+ // If there are no window layers, we treat the display has having FB
+ // composition, because SurfaceFlinger will use GLES to draw the
+ // wormhole region.
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ DisplayData& disp(mDisplayData[i]);
+ disp.hasFbComp = false;
+ disp.hasOvComp = false;
+ if (disp.list) {
+ for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
+ hwc_layer_1_t& l = disp.list->hwLayers[i];
+
+ //ALOGD("prepare: %d, type=%d, handle=%p",
+ // i, l.compositionType, l.handle);
+
+ if (l.flags & HWC_SKIP_LAYER) {
+ l.compositionType = HWC_FRAMEBUFFER;
+ }
+ if (l.compositionType == HWC_FRAMEBUFFER) {
+ disp.hasFbComp = true;
+ }
+ if (l.compositionType == HWC_OVERLAY) {
+ disp.hasOvComp = true;
+ }
+ if (l.compositionType == HWC_CURSOR_OVERLAY) {
+ disp.hasOvComp = true;
+ }
+ }
+ if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) {
+ disp.hasFbComp = true;
+ }
+ } else {
+ disp.hasFbComp = true;
+ }
+ }
+ }
+ return (status_t)err;
+}
+
+bool HWComposer::hasHwcComposition(int32_t id) const {
+ if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ return false;
+ return mDisplayData[id].hasOvComp;
+}
+
+bool HWComposer::hasGlesComposition(int32_t id) const {
+ if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ return true;
+ return mDisplayData[id].hasFbComp;
+}
+
+sp<Fence> HWComposer::getAndResetReleaseFence(int32_t id) {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ return Fence::NO_FENCE;
+
+ int fd = INVALID_OPERATION;
+ if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ const DisplayData& disp(mDisplayData[id]);
+ if (disp.framebufferTarget) {
+ fd = disp.framebufferTarget->releaseFenceFd;
+ disp.framebufferTarget->acquireFenceFd = -1;
+ disp.framebufferTarget->releaseFenceFd = -1;
+ }
+ }
+ return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE;
+}
+
+status_t HWComposer::commit() {
+ int err = NO_ERROR;
+ if (mHwc) {
+ if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // On version 1.0, the OpenGL ES target surface is communicated
+ // by the (dpy, sur) fields and we are guaranteed to have only
+ // a single display.
+ mLists[0]->dpy = eglGetCurrentDisplay();
+ mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW);
+ }
+
+ for (size_t i=VIRTUAL_DISPLAY_ID_BASE; i<mNumDisplays; i++) {
+ DisplayData& disp(mDisplayData[i]);
+ if (disp.outbufHandle) {
+ mLists[i]->outbuf = disp.outbufHandle;
+ mLists[i]->outbufAcquireFenceFd =
+ disp.outbufAcquireFence->dup();
+ }
+ }
+
+ err = mHwc->set(mHwc, mNumDisplays, mLists);
+
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ DisplayData& disp(mDisplayData[i]);
+ disp.lastDisplayFence = disp.lastRetireFence;
+ disp.lastRetireFence = Fence::NO_FENCE;
+ if (disp.list) {
+ if (disp.list->retireFenceFd != -1) {
+ disp.lastRetireFence = new Fence(disp.list->retireFenceFd);
+ disp.list->retireFenceFd = -1;
+ }
+ disp.list->flags &= ~HWC_GEOMETRY_CHANGED;
+ }
+ }
+ }
+ return (status_t)err;
+}
+
+status_t HWComposer::setPowerMode(int disp, int mode) {
+ LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE);
+ if (mHwc) {
+ if (mode == HWC_POWER_MODE_OFF) {
+ eventControl(disp, HWC_EVENT_VSYNC, 0);
+ }
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
+ return (status_t)mHwc->setPowerMode(mHwc, disp, mode);
+ } else {
+ return (status_t)mHwc->blank(mHwc, disp,
+ mode == HWC_POWER_MODE_OFF ? 1 : 0);
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t HWComposer::setActiveConfig(int disp, int mode) {
+ LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE);
+ DisplayData& dd(mDisplayData[disp]);
+ dd.currentConfig = mode;
+ if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
+ return (status_t)mHwc->setActiveConfig(mHwc, disp, mode);
+ } else {
+ LOG_FATAL_IF(mode != 0);
+ }
+ return NO_ERROR;
+}
+
+void HWComposer::disconnectDisplay(int disp) {
+ LOG_ALWAYS_FATAL_IF(disp < 0 || disp == HWC_DISPLAY_PRIMARY);
+ DisplayData& dd(mDisplayData[disp]);
+ free(dd.list);
+ dd.list = NULL;
+ dd.framebufferTarget = NULL; // points into dd.list
+ dd.fbTargetHandle = NULL;
+ dd.outbufHandle = NULL;
+ dd.lastRetireFence = Fence::NO_FENCE;
+ dd.lastDisplayFence = Fence::NO_FENCE;
+ dd.outbufAcquireFence = Fence::NO_FENCE;
+ // clear all the previous configs and repopulate when a new
+ // device is added
+ dd.configs.clear();
+}
+
+int HWComposer::getVisualID() const {
+ if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
+ // is supported by the implementation. we can only be in this case
+ // if we have HWC 1.1
+ return HAL_PIXEL_FORMAT_RGBA_8888;
+ //return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ } else {
+ return mFbDev->format;
+ }
+}
+
+bool HWComposer::supportsFramebufferTarget() const {
+ return (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
+}
+
+int HWComposer::fbPost(int32_t id,
+ const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
+ if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ return setFramebufferTarget(id, acquireFence, buffer);
+ } else {
+ acquireFence->waitForever("HWComposer::fbPost");
+ return mFbDev->post(mFbDev, buffer->handle);
+ }
+}
+
+int HWComposer::fbCompositionComplete() {
+ if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
+ return NO_ERROR;
+
+ if (mFbDev->compositionComplete) {
+ return mFbDev->compositionComplete(mFbDev);
+ } else {
+ return INVALID_OPERATION;
+ }
+}
+
+void HWComposer::fbDump(String8& result) {
+ if (mFbDev && mFbDev->common.version >= 1 && mFbDev->dump) {
+ const size_t SIZE = 4096;
+ char buffer[SIZE];
+ mFbDev->dump(mFbDev, buffer, SIZE);
+ result.append(buffer);
+ }
+}
+
+status_t HWComposer::setOutputBuffer(int32_t id, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& buf) {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ return BAD_INDEX;
+ if (id < VIRTUAL_DISPLAY_ID_BASE)
+ return INVALID_OPERATION;
+
+ DisplayData& disp(mDisplayData[id]);
+ disp.outbufHandle = buf->handle;
+ disp.outbufAcquireFence = acquireFence;
+ return NO_ERROR;
+}
+
+sp<Fence> HWComposer::getLastRetireFence(int32_t id) const {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ return Fence::NO_FENCE;
+ return mDisplayData[id].lastRetireFence;
+}
+
+status_t HWComposer::setCursorPositionAsync(int32_t id, const Rect& pos)
+{
+ if (mHwc->setCursorPositionAsync) {
+ return (status_t)mHwc->setCursorPositionAsync(mHwc, id, pos.left, pos.top);
+ }
+ else {
+ return NO_ERROR;
+ }
+}
+
+/*
+ * Helper template to implement a concrete HWCLayer
+ * This holds the pointer to the concrete hwc layer type
+ * and implements the "iterable" side of HWCLayer.
+ */
+template<typename CONCRETE, typename HWCTYPE>
+class Iterable : public HWComposer::HWCLayer {
+protected:
+ HWCTYPE* const mLayerList;
+ HWCTYPE* mCurrentLayer;
+ Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer) { }
+ inline HWCTYPE const * getLayer() const { return mCurrentLayer; }
+ inline HWCTYPE* getLayer() { return mCurrentLayer; }
+ virtual ~Iterable() { }
+private:
+ // returns a copy of ourselves
+ virtual HWComposer::HWCLayer* dup() {
+ return new CONCRETE( static_cast<const CONCRETE&>(*this) );
+ }
+ virtual status_t setLayer(size_t index) {
+ mCurrentLayer = &mLayerList[index];
+ return NO_ERROR;
+ }
+};
+
+/*
+ * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0.
+ * This implements the HWCLayer side of HWCIterableLayer.
+ */
+class HWCLayerVersion1 : public Iterable<HWCLayerVersion1, hwc_layer_1_t> {
+ struct hwc_composer_device_1* mHwc;
+public:
+ HWCLayerVersion1(struct hwc_composer_device_1* hwc, hwc_layer_1_t* layer)
+ : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer), mHwc(hwc) { }
+
+ virtual int32_t getCompositionType() const {
+ return getLayer()->compositionType;
+ }
+ virtual uint32_t getHints() const {
+ return getLayer()->hints;
+ }
+ virtual sp<Fence> getAndResetReleaseFence() {
+ int fd = getLayer()->releaseFenceFd;
+ getLayer()->releaseFenceFd = -1;
+ return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE;
+ }
+ virtual void setAcquireFenceFd(int fenceFd) {
+ getLayer()->acquireFenceFd = fenceFd;
+ }
+ virtual void setPerFrameDefaultState() {
+ //getLayer()->compositionType = HWC_FRAMEBUFFER;
+ }
+ virtual void setPlaneAlpha(uint8_t alpha) {
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
+ getLayer()->planeAlpha = alpha;
+ } else {
+ if (alpha < 0xFF) {
+ getLayer()->flags |= HWC_SKIP_LAYER;
+ }
+ }
+ }
+ virtual void setDefaultState() {
+ hwc_layer_1_t* const l = getLayer();
+ l->compositionType = HWC_FRAMEBUFFER;
+ l->hints = 0;
+ l->flags = HWC_SKIP_LAYER;
+ l->handle = 0;
+ l->transform = 0;
+ l->blending = HWC_BLENDING_NONE;
+ l->visibleRegionScreen.numRects = 0;
+ l->visibleRegionScreen.rects = NULL;
+ l->acquireFenceFd = -1;
+ l->releaseFenceFd = -1;
+ l->planeAlpha = 0xFF;
+ }
+ virtual void setSkip(bool skip) {
+ if (skip) {
+ getLayer()->flags |= HWC_SKIP_LAYER;
+ } else {
+ getLayer()->flags &= ~HWC_SKIP_LAYER;
+ }
+ }
+ virtual void setIsCursorLayerHint(bool isCursor) {
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
+ if (isCursor) {
+ getLayer()->flags |= HWC_IS_CURSOR_LAYER;
+ }
+ else {
+ getLayer()->flags &= ~HWC_IS_CURSOR_LAYER;
+ }
+ }
+ }
+ virtual void setBlending(uint32_t blending) {
+ getLayer()->blending = blending;
+ }
+ virtual void setTransform(uint32_t transform) {
+ getLayer()->transform = transform;
+ }
+ virtual void setFrame(const Rect& frame) {
+ getLayer()->displayFrame = reinterpret_cast<hwc_rect_t const&>(frame);
+ }
+ virtual void setCrop(const FloatRect& crop) {
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+ getLayer()->sourceCropf = reinterpret_cast<hwc_frect_t const&>(crop);
+ } else {
+ /*
+ * Since h/w composer didn't support a flot crop rect before version 1.3,
+ * using integer coordinates instead produces a different output from the GL code in
+ * Layer::drawWithOpenGL(). The difference can be large if the buffer crop to
+ * window size ratio is large and a window crop is defined
+ * (i.e.: if we scale the buffer a lot and we also crop it with a window crop).
+ */
+ hwc_rect_t& r = getLayer()->sourceCrop;
+ r.left = int(ceilf(crop.left));
+ r.top = int(ceilf(crop.top));
+ r.right = int(floorf(crop.right));
+ r.bottom= int(floorf(crop.bottom));
+ }
+ }
+ virtual void setVisibleRegionScreen(const Region& reg) {
+ hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen;
+ mVisibleRegion = reg;
+ visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(
+ mVisibleRegion.getArray(&visibleRegion.numRects));
+ }
+ virtual void setSurfaceDamage(const Region& reg) {
+ if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_5)) {
+ return;
+ }
+ hwc_region_t& surfaceDamage = getLayer()->surfaceDamage;
+ // We encode default full-screen damage as INVALID_RECT upstream, but as
+ // 0 rects for HWComposer
+ if (reg.isRect() && reg.getBounds() == Rect::INVALID_RECT) {
+ surfaceDamage.numRects = 0;
+ surfaceDamage.rects = NULL;
+ return;
+ }
+ mSurfaceDamage = reg;
+ surfaceDamage.rects = reinterpret_cast<hwc_rect_t const *>(
+ mSurfaceDamage.getArray(&surfaceDamage.numRects));
+ }
+ virtual void setSidebandStream(const sp<NativeHandle>& stream) {
+ ALOG_ASSERT(stream->handle() != NULL);
+ getLayer()->compositionType = HWC_SIDEBAND;
+ getLayer()->sidebandStream = stream->handle();
+ }
+ virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
+ if (buffer == 0 || buffer->handle == 0) {
+ getLayer()->compositionType = HWC_FRAMEBUFFER;
+ getLayer()->flags |= HWC_SKIP_LAYER;
+ getLayer()->handle = 0;
+ } else {
+ if (getLayer()->compositionType == HWC_SIDEBAND) {
+ // If this was a sideband layer but the stream was removed, reset
+ // it to FRAMEBUFFER. The HWC can change it to OVERLAY in prepare.
+ getLayer()->compositionType = HWC_FRAMEBUFFER;
+ }
+ getLayer()->handle = buffer->handle;
+ }
+ }
+ virtual void onDisplayed() {
+ getLayer()->acquireFenceFd = -1;
+ }
+
+protected:
+ // We need to hold "copies" of these for memory management purposes. The
+ // actual hwc_layer_1_t holds pointers to the memory within. Vector<>
+ // internally doesn't copy the memory unless one of the copies is modified.
+ Region mVisibleRegion;
+ Region mSurfaceDamage;
+};
+
+/*
+ * returns an iterator initialized at a given index in the layer list
+ */
+HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+ return LayerListIterator();
+ }
+ const DisplayData& disp(mDisplayData[id]);
+ if (!mHwc || !disp.list || index > disp.list->numHwLayers) {
+ return LayerListIterator();
+ }
+ return LayerListIterator(new HWCLayerVersion1(mHwc, disp.list->hwLayers), index);
+}
+
+/*
+ * returns an iterator on the beginning of the layer list
+ */
+HWComposer::LayerListIterator HWComposer::begin(int32_t id) {
+ return getLayerIterator(id, 0);
+}
+
+/*
+ * returns an iterator on the end of the layer list
+ */
+HWComposer::LayerListIterator HWComposer::end(int32_t id) {
+ size_t numLayers = 0;
+ if (uint32_t(id) <= 31 && mAllocatedDisplayIDs.hasBit(id)) {
+ const DisplayData& disp(mDisplayData[id]);
+ if (mHwc && disp.list) {
+ numLayers = disp.list->numHwLayers;
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // with HWC 1.1, the last layer is always the HWC_FRAMEBUFFER_TARGET,
+ // which we ignore when iterating through the layer list.
+ ALOGE_IF(!numLayers, "mDisplayData[%d].list->numHwLayers is 0", id);
+ if (numLayers) {
+ numLayers--;
+ }
+ }
+ }
+ }
+ return getLayerIterator(id, numLayers);
+}
+
+// Converts a PixelFormat to a human-readable string. Max 11 chars.
+// (Could use a table of prefab String8 objects.)
+static String8 getFormatStr(PixelFormat format) {
+ switch (format) {
+ case PIXEL_FORMAT_RGBA_8888: return String8("RGBA_8888");
+ case PIXEL_FORMAT_RGBX_8888: return String8("RGBx_8888");
+ case PIXEL_FORMAT_RGB_888: return String8("RGB_888");
+ case PIXEL_FORMAT_RGB_565: return String8("RGB_565");
+ case PIXEL_FORMAT_BGRA_8888: return String8("BGRA_8888");
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ return String8("ImplDef");
+ default:
+ String8 result;
+ result.appendFormat("? %08x", format);
+ return result;
+ }
+}
+
+void HWComposer::dump(String8& result) const {
+ Mutex::Autolock _l(mDisplayLock);
+ if (mHwc) {
+ result.appendFormat("Hardware Composer state (version %08x):\n", hwcApiVersion(mHwc));
+ result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ const DisplayData& disp(mDisplayData[i]);
+ if (!disp.connected)
+ continue;
+
+ const Vector< sp<Layer> >& visibleLayersSortedByZ =
+ mFlinger->getLayerSortedByZForHwcDisplay(i);
+
+
+ result.appendFormat(" Display[%zd] configurations (* current):\n", i);
+ for (size_t c = 0; c < disp.configs.size(); ++c) {
+ const DisplayConfig& config(disp.configs[c]);
+ result.appendFormat(" %s%zd: %ux%u, xdpi=%f, ydpi=%f"
+ ", refresh=%" PRId64 ", colorTransform=%d\n",
+ c == disp.currentConfig ? "* " : "", c,
+ config.width, config.height, config.xdpi, config.ydpi,
+ config.refresh, config.colorTransform);
+ }
+
+ if (disp.list) {
+ result.appendFormat(
+ " numHwLayers=%zu, flags=%08x\n",
+ disp.list->numHwLayers, disp.list->flags);
+
+ result.append(
+ " type | handle | hint | flag | tr | blnd | format | source crop (l,t,r,b) | frame | name \n"
+ "-----------+----------+------+------+----+------+-------------+--------------------------------+------------------------+------\n");
+ // " _________ | ________ | ____ | ____ | __ | ____ | ___________ |_____._,_____._,_____._,_____._ |_____,_____,_____,_____ | ___...
+ for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
+ const hwc_layer_1_t&l = disp.list->hwLayers[i];
+ int32_t format = -1;
+ String8 name("unknown");
+
+ if (i < visibleLayersSortedByZ.size()) {
+ const sp<Layer>& layer(visibleLayersSortedByZ[i]);
+ const sp<GraphicBuffer>& buffer(
+ layer->getActiveBuffer());
+ if (buffer != NULL) {
+ format = buffer->getPixelFormat();
+ }
+ name = layer->getName();
+ }
+
+ int type = l.compositionType;
+ if (type == HWC_FRAMEBUFFER_TARGET) {
+ name = "HWC_FRAMEBUFFER_TARGET";
+ format = disp.format;
+ }
+
+ static char const* compositionTypeName[] = {
+ "GLES",
+ "HWC",
+ "BKGND",
+ "FB TARGET",
+ "SIDEBAND",
+ "HWC_CURSOR",
+ "UNKNOWN"};
+ if (type >= NELEM(compositionTypeName))
+ type = NELEM(compositionTypeName) - 1;
+
+ String8 formatStr = getFormatStr(format);
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+ result.appendFormat(
+ " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7.1f,%7.1f,%7.1f,%7.1f |%5d,%5d,%5d,%5d | %s\n",
+ compositionTypeName[type],
+ intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(),
+ l.sourceCropf.left, l.sourceCropf.top, l.sourceCropf.right, l.sourceCropf.bottom,
+ l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
+ name.string());
+ } else {
+ result.appendFormat(
+ " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7d,%7d,%7d,%7d |%5d,%5d,%5d,%5d | %s\n",
+ compositionTypeName[type],
+ intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(),
+ l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
+ l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
+ name.string());
+ }
+ }
+ }
+ }
+ }
+
+ if (mHwc && mHwc->dump) {
+ const size_t SIZE = 4096;
+ char buffer[SIZE];
+ mHwc->dump(mHwc, buffer, SIZE);
+ result.append(buffer);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+HWComposer::VSyncThread::VSyncThread(HWComposer& hwc)
+ : mHwc(hwc), mEnabled(false),
+ mNextFakeVSync(0),
+ mRefreshPeriod(hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY))
+{
+}
+
+void HWComposer::VSyncThread::setEnabled(bool enabled) {
+ Mutex::Autolock _l(mLock);
+ if (mEnabled != enabled) {
+ mEnabled = enabled;
+ mCondition.signal();
+ }
+}
+
+void HWComposer::VSyncThread::onFirstRef() {
+ run("VSyncThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
+}
+
+bool HWComposer::VSyncThread::threadLoop() {
+ { // scope for lock
+ Mutex::Autolock _l(mLock);
+ while (!mEnabled) {
+ mCondition.wait(mLock);
+ }
+ }
+
+ const nsecs_t period = mRefreshPeriod;
+ const nsecs_t now = systemTime(CLOCK_MONOTONIC);
+ nsecs_t next_vsync = mNextFakeVSync;
+ nsecs_t sleep = next_vsync - now;
+ if (sleep < 0) {
+ // we missed, find where the next vsync should be
+ sleep = (period - ((now - next_vsync) % period));
+ next_vsync = now + sleep;
+ }
+ mNextFakeVSync = next_vsync + period;
+
+ struct timespec spec;
+ spec.tv_sec = next_vsync / 1000000000;
+ spec.tv_nsec = next_vsync % 1000000000;
+
+ int err;
+ do {
+ err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
+ } while (err<0 && errno == EINTR);
+
+ if (err == 0) {
+ mHwc.mEventHandler.onVSyncReceived(0, next_vsync);
+ }
+
+ return true;
+}
+
+HWComposer::DisplayData::DisplayData()
+: configs(),
+ currentConfig(0),
+ format(HAL_PIXEL_FORMAT_RGBA_8888),
+ connected(false),
+ hasFbComp(false), hasOvComp(false),
+ capacity(0), list(NULL),
+ framebufferTarget(NULL), fbTargetHandle(0),
+ lastRetireFence(Fence::NO_FENCE), lastDisplayFence(Fence::NO_FENCE),
+ outbufHandle(NULL), outbufAcquireFence(Fence::NO_FENCE),
+ events(0)
+{}
+
+HWComposer::DisplayData::~DisplayData() {
+ free(list);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
new file mode 100644
index 0000000..f5f7d77
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SF_HWCOMPOSER_HWC1_H
+#define ANDROID_SF_HWCOMPOSER_HWC1_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware/hwcomposer_defs.h>
+
+#include <ui/Fence.h>
+
+#include <utils/BitSet.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
+#include <utils/Thread.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
+extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
+ const struct timespec *request,
+ struct timespec *remain);
+
+struct hwc_composer_device_1;
+struct hwc_display_contents_1;
+struct hwc_layer_1;
+struct hwc_procs;
+struct framebuffer_device_t;
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Fence;
+class FloatRect;
+class GraphicBuffer;
+class NativeHandle;
+class Region;
+class String8;
+class SurfaceFlinger;
+
+class HWComposer
+{
+public:
+ class EventHandler {
+ friend class HWComposer;
+ virtual void onVSyncReceived(int disp, nsecs_t timestamp) = 0;
+ virtual void onHotplugReceived(int disp, bool connected) = 0;
+ protected:
+ virtual ~EventHandler() {}
+ };
+
+ enum {
+ NUM_BUILTIN_DISPLAYS = HWC_NUM_PHYSICAL_DISPLAY_TYPES,
+ MAX_HWC_DISPLAYS = HWC_NUM_DISPLAY_TYPES,
+ VIRTUAL_DISPLAY_ID_BASE = HWC_DISPLAY_VIRTUAL,
+ };
+
+ HWComposer(
+ const sp<SurfaceFlinger>& flinger,
+ EventHandler& handler);
+
+ ~HWComposer();
+
+ status_t initCheck() const;
+
+ // Returns a display ID starting at VIRTUAL_DISPLAY_ID_BASE, this ID is to
+ // be used with createWorkList (and all other methods requiring an ID
+ // below).
+ // IDs below NUM_BUILTIN_DISPLAYS are pre-defined and therefore are
+ // always valid.
+ // Returns -1 if an ID cannot be allocated
+ int32_t allocateDisplayId();
+
+ // Recycles the given virtual display ID and frees the associated worklist.
+ // IDs below NUM_BUILTIN_DISPLAYS are not recycled.
+ status_t freeDisplayId(int32_t id);
+
+
+ // Asks the HAL what it can do
+ status_t prepare();
+
+ // commits the list
+ status_t commit();
+
+ // set power mode
+ status_t setPowerMode(int disp, int mode);
+
+ // set active config
+ status_t setActiveConfig(int disp, int mode);
+
+ // reset state when an external, non-virtual display is disconnected
+ void disconnectDisplay(int disp);
+
+ // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
+ status_t createWorkList(int32_t id, size_t numLayers);
+
+ bool supportsFramebufferTarget() const;
+
+ // does this display have layers handled by HWC
+ bool hasHwcComposition(int32_t id) const;
+
+ // does this display have layers handled by GLES
+ bool hasGlesComposition(int32_t id) const;
+
+ // get the releaseFence file descriptor for a display's framebuffer layer.
+ // the release fence is only valid after commit()
+ sp<Fence> getAndResetReleaseFence(int32_t id);
+
+ // needed forward declarations
+ class LayerListIterator;
+
+ // return the visual id to be used to find a suitable EGLConfig for
+ // *ALL* displays.
+ int getVisualID() const;
+
+ // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface).
+ int fbPost(int32_t id, const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
+ int fbCompositionComplete();
+ void fbDump(String8& result);
+
+ // Set the output buffer and acquire fence for a virtual display.
+ // Returns INVALID_OPERATION if id is not a virtual display.
+ status_t setOutputBuffer(int32_t id, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& buf);
+
+ // Get the retire fence for the last committed frame. This fence will
+ // signal when the h/w composer is completely finished with the frame.
+ // For physical displays, it is no longer being displayed. For virtual
+ // displays, writes to the output buffer are complete.
+ sp<Fence> getLastRetireFence(int32_t id) const;
+
+ status_t setCursorPositionAsync(int32_t id, const Rect &pos);
+
+ /*
+ * Interface to hardware composer's layers functionality.
+ * This abstracts the HAL interface to layers which can evolve in
+ * incompatible ways from one release to another.
+ * The idea is that we could extend this interface as we add
+ * features to h/w composer.
+ */
+ class HWCLayerInterface {
+ protected:
+ virtual ~HWCLayerInterface() { }
+ public:
+ virtual int32_t getCompositionType() const = 0;
+ virtual uint32_t getHints() const = 0;
+ virtual sp<Fence> getAndResetReleaseFence() = 0;
+ virtual void setDefaultState() = 0;
+ virtual void setSkip(bool skip) = 0;
+ virtual void setIsCursorLayerHint(bool isCursor = true) = 0;
+ virtual void setBlending(uint32_t blending) = 0;
+ virtual void setTransform(uint32_t transform) = 0;
+ virtual void setFrame(const Rect& frame) = 0;
+ virtual void setCrop(const FloatRect& crop) = 0;
+ virtual void setVisibleRegionScreen(const Region& reg) = 0;
+ virtual void setSurfaceDamage(const Region& reg) = 0;
+ virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0;
+ virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
+ virtual void setAcquireFenceFd(int fenceFd) = 0;
+ virtual void setPlaneAlpha(uint8_t alpha) = 0;
+ virtual void onDisplayed() = 0;
+ };
+
+ /*
+ * Interface used to implement an iterator to a list
+ * of HWCLayer.
+ */
+ class HWCLayer : public HWCLayerInterface {
+ friend class LayerListIterator;
+ // select the layer at the given index
+ virtual status_t setLayer(size_t index) = 0;
+ virtual HWCLayer* dup() = 0;
+ static HWCLayer* copy(HWCLayer *rhs) {
+ return rhs ? rhs->dup() : NULL;
+ }
+ protected:
+ virtual ~HWCLayer() { }
+ };
+
+ /*
+ * Iterator through a HWCLayer list.
+ * This behaves more or less like a forward iterator.
+ */
+ class LayerListIterator {
+ friend class HWComposer;
+ HWCLayer* const mLayerList;
+ size_t mIndex;
+
+ LayerListIterator() : mLayerList(NULL), mIndex(0) { }
+
+ LayerListIterator(HWCLayer* layer, size_t index)
+ : mLayerList(layer), mIndex(index) { }
+
+ // we don't allow assignment, because we don't need it for now
+ LayerListIterator& operator = (const LayerListIterator& rhs);
+
+ public:
+ // copy operators
+ LayerListIterator(const LayerListIterator& rhs)
+ : mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) {
+ }
+
+ ~LayerListIterator() { delete mLayerList; }
+
+ // pre-increment
+ LayerListIterator& operator++() {
+ mLayerList->setLayer(++mIndex);
+ return *this;
+ }
+
+ // dereference
+ HWCLayerInterface& operator * () { return *mLayerList; }
+ HWCLayerInterface* operator -> () { return mLayerList; }
+
+ // comparison
+ bool operator == (const LayerListIterator& rhs) const {
+ return mIndex == rhs.mIndex;
+ }
+ bool operator != (const LayerListIterator& rhs) const {
+ return !operator==(rhs);
+ }
+ };
+
+ // Returns an iterator to the beginning of the layer list
+ LayerListIterator begin(int32_t id);
+
+ // Returns an iterator to the end of the layer list
+ LayerListIterator end(int32_t id);
+
+
+ // Events handling ---------------------------------------------------------
+
+ enum {
+ EVENT_VSYNC = HWC_EVENT_VSYNC
+ };
+
+ void eventControl(int disp, int event, int enabled);
+
+ struct DisplayConfig {
+ uint32_t width;
+ uint32_t height;
+ float xdpi;
+ float ydpi;
+ nsecs_t refresh;
+ int colorTransform;
+ };
+
+ // Query display parameters. Pass in a display index (e.g.
+ // HWC_DISPLAY_PRIMARY).
+ nsecs_t getRefreshTimestamp(int disp) const;
+ sp<Fence> getDisplayFence(int disp) const;
+ uint32_t getFormat(int disp) const;
+ bool isConnected(int disp) const;
+
+ // These return the values for the current config of a given display index.
+ // To get the values for all configs, use getConfigs below.
+ uint32_t getWidth(int disp) const;
+ uint32_t getHeight(int disp) const;
+ float getDpiX(int disp) const;
+ float getDpiY(int disp) const;
+ nsecs_t getRefreshPeriod(int disp) const;
+
+ const Vector<DisplayConfig>& getConfigs(int disp) const;
+ size_t getCurrentConfig(int disp) const;
+
+ status_t setVirtualDisplayProperties(int32_t id, uint32_t w, uint32_t h,
+ uint32_t format);
+
+ // this class is only used to fake the VSync event on systems that don't
+ // have it.
+ class VSyncThread : public Thread {
+ HWComposer& mHwc;
+ mutable Mutex mLock;
+ Condition mCondition;
+ bool mEnabled;
+ mutable nsecs_t mNextFakeVSync;
+ nsecs_t mRefreshPeriod;
+ virtual void onFirstRef();
+ virtual bool threadLoop();
+ public:
+ VSyncThread(HWComposer& hwc);
+ void setEnabled(bool enabled);
+ };
+
+ friend class VSyncThread;
+
+ // for debugging ----------------------------------------------------------
+ void dump(String8& out) const;
+
+private:
+ void loadHwcModule();
+ int loadFbHalModule();
+
+ LayerListIterator getLayerIterator(int32_t id, size_t index);
+
+ struct cb_context;
+
+ static void hook_invalidate(const struct hwc_procs* procs);
+ static void hook_vsync(const struct hwc_procs* procs, int disp,
+ int64_t timestamp);
+ static void hook_hotplug(const struct hwc_procs* procs, int disp,
+ int connected);
+
+ inline void invalidate();
+ inline void vsync(int disp, int64_t timestamp);
+ inline void hotplug(int disp, int connected);
+
+ status_t queryDisplayProperties(int disp);
+
+ status_t setFramebufferTarget(int32_t id,
+ const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
+
+ struct DisplayData {
+ DisplayData();
+ ~DisplayData();
+ Vector<DisplayConfig> configs;
+ size_t currentConfig;
+ uint32_t format; // pixel format from FB hal, for pre-hwc-1.1
+ bool connected;
+ bool hasFbComp;
+ bool hasOvComp;
+ size_t capacity;
+ hwc_display_contents_1* list;
+ hwc_layer_1* framebufferTarget;
+ buffer_handle_t fbTargetHandle;
+ sp<Fence> lastRetireFence; // signals when the last set op retires
+ sp<Fence> lastDisplayFence; // signals when the last set op takes
+ // effect on screen
+ buffer_handle_t outbufHandle;
+ sp<Fence> outbufAcquireFence;
+
+ // protected by mEventControlLock
+ int32_t events;
+ };
+
+ sp<SurfaceFlinger> mFlinger;
+ framebuffer_device_t* mFbDev;
+ struct hwc_composer_device_1* mHwc;
+ // invariant: mLists[0] != NULL iff mHwc != NULL
+ // mLists[i>0] can be NULL. that display is to be ignored
+ struct hwc_display_contents_1* mLists[MAX_HWC_DISPLAYS];
+ DisplayData mDisplayData[MAX_HWC_DISPLAYS];
+ // protect mDisplayData from races between prepare and dump
+ mutable Mutex mDisplayLock;
+ size_t mNumDisplays;
+
+ cb_context* mCBContext;
+ EventHandler& mEventHandler;
+ size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
+ sp<VSyncThread> mVSyncThread;
+ bool mDebugForceFakeVSync;
+ BitSet32 mAllocatedDisplayIDs;
+
+ // protected by mLock
+ mutable Mutex mLock;
+ mutable nsecs_t mLastHwVSync[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
+
+ // thread-safe
+ mutable Mutex mEventControlLock;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 1a0d689..1afed36 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -57,8 +57,20 @@
mHwc(hwc),
mDisplayId(dispId),
mDisplayName(name),
+ mSource{},
+ mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+ mOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
mProducerSlotSource(0),
+ mProducerBuffers(),
+ mQueueBufferOutput(),
+ mSinkBufferWidth(0),
+ mSinkBufferHeight(0),
+ mCompositionType(COMPOSITION_UNKNOWN),
+ mFbFence(Fence::NO_FENCE),
+ mOutputFence(Fence::NO_FENCE),
+ mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
mDbgState(DBG_STATE_IDLE),
mDbgLastCompositionType(COMPOSITION_UNKNOWN),
mMustRecompose(false)
@@ -163,9 +175,11 @@
return NO_ERROR;
}
+#ifndef USE_HWC2
status_t VirtualDisplaySurface::compositionComplete() {
return NO_ERROR;
}
+#endif
status_t VirtualDisplaySurface::advanceFrame() {
if (mDisplayId < 0)
@@ -206,7 +220,13 @@
status_t result = NO_ERROR;
if (fbBuffer != NULL) {
+#ifdef USE_HWC2
+ // TODO: Correctly propagate the dataspace from GL composition
+ result = mHwc.setClientTarget(mDisplayId, mFbFence, fbBuffer,
+ HAL_DATASPACE_UNKNOWN);
+#else
result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
+#endif
}
return result;
@@ -220,13 +240,22 @@
"Unexpected onFrameCommitted() in %s state", dbgStateStr());
mDbgState = DBG_STATE_IDLE;
+#ifdef USE_HWC2
+ sp<Fence> retireFence = mHwc.getRetireFence(mDisplayId);
+#else
sp<Fence> fbFence = mHwc.getAndResetReleaseFence(mDisplayId);
+#endif
if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) {
// release the scratch buffer back to the pool
Mutex::Autolock lock(mMutex);
int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot);
VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot);
+#ifdef USE_HWC2
+ addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot],
+ retireFence);
+#else
addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence);
+#endif
releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot],
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
}
@@ -234,7 +263,9 @@
if (mOutputProducerSlot >= 0) {
int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot);
QueueBufferOutput qbo;
+#ifndef USE_HWC2
sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId);
+#endif
VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot);
if (mMustRecompose) {
status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
@@ -243,7 +274,11 @@
HAL_DATASPACE_UNKNOWN,
Rect(mSinkBufferWidth, mSinkBufferHeight),
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */,
+#ifdef USE_HWC2
+ retireFence),
+#else
outFence),
+#endif
&qbo);
if (result == NO_ERROR) {
updateQueueBufferOutput(qbo);
@@ -253,7 +288,11 @@
// through the motions of updating the display to keep our state
// machine happy. We cancel the buffer to avoid triggering another
// re-composition and causing an infinite loop.
+#ifdef USE_HWC2
+ mSource[SOURCE_SINK]->cancelBuffer(sslot, retireFence);
+#else
mSource[SOURCE_SINK]->cancelBuffer(sslot, outFence);
+#endif
}
}
@@ -272,6 +311,12 @@
mSinkBufferHeight = h;
}
+#ifdef USE_HWC2
+const sp<Fence>& VirtualDisplaySurface::getClientTargetAcquireFence() const {
+ return mFbFence;
+}
+#endif
+
status_t VirtualDisplaySurface::requestBuffer(int pslot,
sp<GraphicBuffer>* outBuf) {
if (mDisplayId < 0)
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index ede204c..fe187c2 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -83,11 +83,16 @@
//
virtual status_t beginFrame(bool mustRecompose);
virtual status_t prepareFrame(CompositionType compositionType);
+#ifndef USE_HWC2
virtual status_t compositionComplete();
+#endif
virtual status_t advanceFrame();
virtual void onFrameCommitted();
virtual void dumpAsString(String8& result) const;
virtual void resizeBuffers(const uint32_t w, const uint32_t h);
+#ifdef USE_HWC2
+ virtual const sp<Fence>& getClientTargetAcquireFence() const override;
+#endif
private:
enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1};
diff --git a/services/surfaceflinger/EventControlThread.cpp b/services/surfaceflinger/EventControlThread.cpp
index 6504091..ee6e886 100644
--- a/services/surfaceflinger/EventControlThread.cpp
+++ b/services/surfaceflinger/EventControlThread.cpp
@@ -35,8 +35,12 @@
bool vsyncEnabled = mVsyncEnabled;
+#ifdef USE_HWC2
+ mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled);
+#else
mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC,
mVsyncEnabled);
+#endif
while (true) {
status_t err = mCond.wait(mMutex);
@@ -47,8 +51,12 @@
}
if (vsyncEnabled != mVsyncEnabled) {
+#ifdef USE_HWC2
+ mFlinger->setVsyncEnabled(HWC_DISPLAY_PRIMARY, mVsyncEnabled);
+#else
mFlinger->eventControl(HWC_DISPLAY_PRIMARY,
SurfaceFlinger::EVENT_VSYNC, mVsyncEnabled);
+#endif
vsyncEnabled = mVsyncEnabled;
}
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 9dca798..04256e1 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "Layer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <stdlib.h>
@@ -90,6 +93,10 @@
mUpdateTexImageFailed(false),
mAutoRefresh(false)
{
+#ifdef USE_HWC2
+ ALOGV("Creating Layer %s", name.string());
+#endif
+
mCurrentCrop.makeInvalid();
mFlinger->getRenderEngine().genTextures(1, &mTextureName);
mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);
@@ -111,7 +118,11 @@
mCurrentState.active.h = h;
mCurrentState.active.crop.makeInvalid();
mCurrentState.z = 0;
+#ifdef USE_HWC2
+ mCurrentState.alpha = 1.0f;
+#else
mCurrentState.alpha = 0xFF;
+#endif
mCurrentState.layerStack = 0;
mCurrentState.flags = layerFlags;
mCurrentState.sequence = 0;
@@ -121,8 +132,14 @@
// drawing state & current state are identical
mDrawingState = mCurrentState;
+#ifdef USE_HWC2
+ const auto& hwc = flinger->getHwComposer();
+ const auto& activeConfig = hwc.getActiveConfig(HWC_DISPLAY_PRIMARY);
+ nsecs_t displayPeriod = activeConfig->getVsyncPeriod();
+#else
nsecs_t displayPeriod =
flinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+#endif
mFrameTracker.setDisplayRefreshPeriod(displayPeriod);
}
@@ -159,6 +176,14 @@
// callbacks
// ---------------------------------------------------------------------------
+#ifdef USE_HWC2
+void Layer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+ if (mHwcLayers.empty()) {
+ return;
+ }
+ mSurfaceFlingerConsumer->setReleaseFence(releaseFence);
+}
+#else
void Layer::onLayerDisplayed(const sp<const DisplayDevice>& /* hw */,
HWComposer::HWCLayerInterface* layer) {
if (layer) {
@@ -166,6 +191,7 @@
mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFence());
}
}
+#endif
void Layer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
@@ -452,26 +478,56 @@
return crop;
}
+#ifdef USE_HWC2
+void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice)
+#else
void Layer::setGeometry(
const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer)
+#endif
{
+#ifdef USE_HWC2
+ const auto hwcId = displayDevice->getHwcDisplayId();
+ auto& hwcInfo = mHwcLayers[hwcId];
+#else
layer.setDefaultState();
+#endif
// enable this layer
+#ifdef USE_HWC2
+ hwcInfo.forceClientComposition = false;
+
+ if (isSecure() && !displayDevice->isSecure()) {
+ hwcInfo.forceClientComposition = true;
+ }
+
+ auto& hwcLayer = hwcInfo.layer;
+#else
layer.setSkip(false);
if (isSecure() && !hw->isSecure()) {
layer.setSkip(true);
}
+#endif
// this gives us only the "orientation" component of the transform
const State& s(getDrawingState());
+#ifdef USE_HWC2
+ if (!isOpaque(s) || s.alpha != 1.0f) {
+ auto blendMode = mPremultipliedAlpha ?
+ HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
+ auto error = hwcLayer->setBlendMode(blendMode);
+ ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set blend mode %s:"
+ " %s (%d)", mName.string(), to_string(blendMode).c_str(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+#else
if (!isOpaque(s) || s.alpha != 0xFF) {
layer.setBlending(mPremultipliedAlpha ?
HWC_BLENDING_PREMULT :
HWC_BLENDING_COVERAGE);
}
+#endif
// apply the layer's transform, followed by the display's global transform
// here we're guaranteed that the layer's transform preserves rects
@@ -479,7 +535,11 @@
if (!s.active.crop.isEmpty()) {
Rect activeCrop(s.active.crop);
activeCrop = s.transform.transform(activeCrop);
+#ifdef USE_HWC2
+ activeCrop.intersect(displayDevice->getViewport(), &activeCrop);
+#else
activeCrop.intersect(hw->getViewport(), &activeCrop);
+#endif
activeCrop = s.transform.inverse().transform(activeCrop);
// This needs to be here as transform.transform(Rect) computes the
// transformed rect and then takes the bounding box of the result before
@@ -498,11 +558,41 @@
s.active.w, activeCrop.bottom));
}
Rect frame(s.transform.transform(computeBounds(activeTransparentRegion)));
+#ifdef USE_HWC2
+ frame.intersect(displayDevice->getViewport(), &frame);
+ const Transform& tr(displayDevice->getTransform());
+ Rect transformedFrame = tr.transform(frame);
+ auto error = hwcLayer->setDisplayFrame(transformedFrame);
+ ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set display frame "
+ "[%d, %d, %d, %d]: %s (%d)", mName.string(), transformedFrame.left,
+ transformedFrame.top, transformedFrame.right,
+ transformedFrame.bottom, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+
+ FloatRect sourceCrop = computeCrop(displayDevice);
+ error = hwcLayer->setSourceCrop(sourceCrop);
+ ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set source crop "
+ "[%.3f, %.3f, %.3f, %.3f]: %s (%d)", mName.string(),
+ sourceCrop.left, sourceCrop.top, sourceCrop.right,
+ sourceCrop.bottom, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+
+ error = hwcLayer->setPlaneAlpha(s.alpha);
+ ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set plane alpha %.3f: "
+ "%s (%d)", mName.string(), s.alpha, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+
+ error = hwcLayer->setZOrder(s.z);
+ ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)",
+ mName.string(), s.z, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+#else
frame.intersect(hw->getViewport(), &frame);
const Transform& tr(hw->getTransform());
layer.setFrame(tr.transform(frame));
layer.setCrop(computeCrop(hw));
layer.setPlaneAlpha(s.alpha);
+#endif
/*
* Transformations are applied in this order:
@@ -519,7 +609,11 @@
/*
* the code below applies the display's inverse transform to the buffer
*/
+#ifdef USE_HWC2
+ uint32_t invTransform = displayDevice->getOrientationTransform();
+#else
uint32_t invTransform = hw->getOrientationTransform();
+#endif
uint32_t t_orientation = transform.getOrientation();
// calculate the inverse transform
if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
@@ -540,14 +634,110 @@
// this gives us only the "orientation" component of the transform
const uint32_t orientation = transform.getOrientation();
+#ifdef USE_HWC2
+ if (orientation & Transform::ROT_INVALID) {
+ // we can only handle simple transformation
+ hwcInfo.forceClientComposition = true;
+ } else {
+ auto transform = static_cast<HWC2::Transform>(orientation);
+ auto error = hwcLayer->setTransform(transform);
+ ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set transform %s: "
+ "%s (%d)", mName.string(), to_string(transform).c_str(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+#else
if (orientation & Transform::ROT_INVALID) {
// we can only handle simple transformation
layer.setSkip(true);
} else {
layer.setTransform(orientation);
}
+#endif
}
+#ifdef USE_HWC2
+void Layer::forceClientComposition(int32_t hwcId) {
+ if (mHwcLayers.count(hwcId) == 0) {
+ ALOGE("forceClientComposition: no HWC layer found (%d)", hwcId);
+ return;
+ }
+
+ mHwcLayers[hwcId].forceClientComposition = true;
+}
+#endif
+
+#ifdef USE_HWC2
+void Layer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
+ // Apply this display's projection's viewport to the visible region
+ // before giving it to the HWC HAL.
+ const Transform& tr = displayDevice->getTransform();
+ const auto& viewport = displayDevice->getViewport();
+ Region visible = tr.transform(visibleRegion.intersect(viewport));
+ auto hwcId = displayDevice->getHwcDisplayId();
+ auto& hwcLayer = mHwcLayers[hwcId].layer;
+ auto error = hwcLayer->setVisibleRegion(visible);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ visible.dump(LOG_TAG);
+ }
+
+ error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ surfaceDamageRegion.dump(LOG_TAG);
+ }
+
+ auto compositionType = HWC2::Composition::Invalid;
+ if (mSidebandStream.get()) {
+ compositionType = HWC2::Composition::Sideband;
+ auto error = hwcLayer->setSidebandStream(mSidebandStream->handle());
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set sideband stream %p: %s (%d)",
+ mName.string(), mSidebandStream->handle(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ return;
+ }
+ } else {
+ if (mActiveBuffer == nullptr || mActiveBuffer->handle == nullptr) {
+ compositionType = HWC2::Composition::Client;
+ auto error = hwcLayer->setBuffer(nullptr, Fence::NO_FENCE);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set null buffer: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ return;
+ }
+ } else {
+ if (mPotentialCursor) {
+ compositionType = HWC2::Composition::Cursor;
+ }
+ auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence();
+ auto error = hwcLayer->setBuffer(mActiveBuffer->handle,
+ acquireFence);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
+ mActiveBuffer->handle, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ return;
+ }
+ // If it's not a cursor, default to device composition
+ }
+ }
+
+ if (mHwcLayers[hwcId].forceClientComposition) {
+ ALOGV("[%s] Forcing Client composition", mName.string());
+ setCompositionType(hwcId, HWC2::Composition::Client);
+ } else if (compositionType != HWC2::Composition::Invalid) {
+ ALOGV("[%s] Requesting %s composition", mName.string(),
+ to_string(compositionType).c_str());
+ setCompositionType(hwcId, compositionType);
+ } else {
+ ALOGV("[%s] Requesting Device composition", mName.string());
+ setCompositionType(hwcId, HWC2::Composition::Device);
+ }
+}
+#else
void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer) {
// we have to set the visible region on every frame because
@@ -568,7 +758,40 @@
layer.setBuffer(mActiveBuffer);
}
}
+#endif
+#ifdef USE_HWC2
+void Layer::updateCursorPosition(const sp<const DisplayDevice>& displayDevice) {
+ auto hwcId = displayDevice->getHwcDisplayId();
+ if (mHwcLayers.count(hwcId) == 0 ||
+ getCompositionType(hwcId) != HWC2::Composition::Cursor) {
+ return;
+ }
+
+ // This gives us only the "orientation" component of the transform
+ const State& s(getCurrentState());
+
+ // Apply the layer's transform, followed by the display's global transform
+ // Here we're guaranteed that the layer's transform preserves rects
+ Rect win(s.active.w, s.active.h);
+ if (!s.active.crop.isEmpty()) {
+ win.intersect(s.active.crop, &win);
+ }
+ // Subtract the transparent region and snap to the bounds
+ Rect bounds = reduce(win, s.activeTransparentRegion);
+ Rect frame(s.transform.transform(bounds));
+ frame.intersect(displayDevice->getViewport(), &frame);
+ auto& displayTransform(displayDevice->getTransform());
+ auto position = displayTransform.transform(frame);
+
+ auto error = mHwcLayers[hwcId].layer->setCursorPosition(position.left,
+ position.top);
+ ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set cursor position "
+ "to (%d, %d): %s (%d)", mName.string(), position.left,
+ position.top, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+}
+#else
void Layer::setAcquireFence(const sp<const DisplayDevice>& /* hw */,
HWComposer::HWCLayerInterface& layer) {
int fenceFd = -1;
@@ -607,6 +830,7 @@
const Transform& tr(hw->getTransform());
return Rect(tr.transform(frame));
}
+#endif
// ---------------------------------------------------------------------------
// drawing...
@@ -778,6 +1002,55 @@
engine.disableBlending();
}
+#ifdef USE_HWC2
+void Layer::setCompositionType(int32_t hwcId, HWC2::Composition type,
+ bool callIntoHwc) {
+ if (mHwcLayers.count(hwcId) == 0) {
+ ALOGE("setCompositionType called without a valid HWC layer");
+ return;
+ }
+ auto& hwcInfo = mHwcLayers[hwcId];
+ auto& hwcLayer = hwcInfo.layer;
+ ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", hwcLayer->getId(),
+ to_string(type).c_str(), static_cast<int>(callIntoHwc));
+ if (hwcInfo.compositionType != type) {
+ ALOGV(" actually setting");
+ hwcInfo.compositionType = type;
+ if (callIntoHwc) {
+ auto error = hwcLayer->setCompositionType(type);
+ ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set "
+ "composition type %s: %s (%d)", mName.string(),
+ to_string(type).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+ }
+}
+
+HWC2::Composition Layer::getCompositionType(int32_t hwcId) const {
+ if (mHwcLayers.count(hwcId) == 0) {
+ ALOGE("getCompositionType called without a valid HWC layer");
+ return HWC2::Composition::Invalid;
+ }
+ return mHwcLayers.at(hwcId).compositionType;
+}
+
+void Layer::setClearClientTarget(int32_t hwcId, bool clear) {
+ if (mHwcLayers.count(hwcId) == 0) {
+ ALOGE("setClearClientTarget called without a valid HWC layer");
+ return;
+ }
+ mHwcLayers[hwcId].clearClientTarget = clear;
+}
+
+bool Layer::getClearClientTarget(int32_t hwcId) const {
+ if (mHwcLayers.count(hwcId) == 0) {
+ ALOGE("getClearClientTarget called without a valid HWC layer");
+ return false;
+ }
+ return mHwcLayers.at(hwcId).clearClientTarget;
+}
+#endif
+
uint32_t Layer::getProducerStickyTransform() const {
int producerStickyTransform = 0;
int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform);
@@ -1179,7 +1452,11 @@
setTransactionFlags(eTransactionNeeded);
return true;
}
+#ifdef USE_HWC2
+bool Layer::setAlpha(float alpha) {
+#else
bool Layer::setAlpha(uint8_t alpha) {
+#endif
if (mCurrentState.alpha == alpha)
return false;
mCurrentState.sequence++;
@@ -1305,7 +1582,11 @@
}
const HWComposer& hwc = mFlinger->getHwComposer();
+#ifdef USE_HWC2
+ sp<Fence> presentFence = hwc.getRetireFence(HWC_DISPLAY_PRIMARY);
+#else
sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
+#endif
if (presentFence->isValid()) {
mFrameTracker.setActualPresentFence(presentFence);
} else {
@@ -1320,10 +1601,21 @@
}
}
+#ifdef USE_HWC2
+void Layer::releasePendingBuffer() {
+ mSurfaceFlingerConsumer->releasePendingBuffer();
+}
+#endif
+
bool Layer::isVisible() const {
const Layer::State& s(mDrawingState);
+#ifdef USE_HWC2
+ return !(s.flags & layer_state_t::eLayerHidden) && s.alpha > 0.0f
+ && (mActiveBuffer != NULL || mSidebandStream != NULL);
+#else
return !(s.flags & layer_state_t::eLayerHidden) && s.alpha
&& (mActiveBuffer != NULL || mSidebandStream != NULL);
+#endif
}
Region Layer::latchBuffer(bool& recomputeVisibleRegions)
@@ -1702,7 +1994,11 @@
result.appendFormat( " "
"layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
"isOpaque=%1d, invalidate=%1d, "
+#ifdef USE_HWC2
+ "alpha=%.3f, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
+#else
"alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
+#endif
" client=%p\n",
s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
s.active.crop.left, s.active.crop.top,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 1773daf..26e1adb 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -107,7 +107,11 @@
Geometry requested;
uint32_t z;
uint32_t layerStack;
+#ifdef USE_HWC2
+ float alpha;
+#else
uint8_t alpha;
+#endif
uint8_t flags;
uint8_t mask;
uint8_t reserved[2];
@@ -141,7 +145,11 @@
bool setPosition(float x, float y);
bool setLayer(uint32_t z);
bool setSize(uint32_t w, uint32_t h);
+#ifdef USE_HWC2
+ bool setAlpha(float alpha);
+#else
bool setAlpha(uint8_t alpha);
+#endif
bool setMatrix(const layer_state_t::matrix22_t& matrix);
bool setTransparentRegionHint(const Region& transparent);
bool setFlags(uint8_t flags, uint8_t mask);
@@ -214,6 +222,22 @@
public:
// -----------------------------------------------------------------------
+#ifdef USE_HWC2
+ void setGeometry(const sp<const DisplayDevice>& displayDevice);
+ void forceClientComposition(int32_t hwcId);
+ void setPerFrameData(const sp<const DisplayDevice>& displayDevice);
+
+ // callIntoHwc exists so we can update our local state and call
+ // acceptDisplayChanges without unnecessarily updating the device's state
+ void setCompositionType(int32_t hwcId, HWC2::Composition type,
+ bool callIntoHwc = true);
+ HWC2::Composition getCompositionType(int32_t hwcId) const;
+
+ void setClearClientTarget(int32_t hwcId, bool clear);
+ bool getClearClientTarget(int32_t hwcId) const;
+
+ void updateCursorPosition(const sp<const DisplayDevice>& hw);
+#else
void setGeometry(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer);
void setPerFrameData(const sp<const DisplayDevice>& hw,
@@ -222,12 +246,17 @@
HWComposer::HWCLayerInterface& layer);
Rect getPosition(const sp<const DisplayDevice>& hw);
+#endif
/*
* called after page-flip
*/
+#ifdef USE_HWC2
+ void onLayerDisplayed(const sp<Fence>& releaseFence);
+#else
void onLayerDisplayed(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface* layer);
+#endif
bool shouldPresentNow(const DispSync& dispSync) const;
@@ -242,6 +271,11 @@
*/
void onPostComposition();
+#ifdef USE_HWC2
+ // If a buffer was replaced this frame, release the former buffer
+ void releasePendingBuffer();
+#endif
+
/*
* draw - performs some global clipping optimizations
* and calls onDraw().
@@ -309,6 +343,37 @@
bool hasQueuedFrame() const { return mQueuedFrames > 0 ||
mSidebandStreamChanged || mAutoRefresh; }
+#ifdef USE_HWC2
+ // -----------------------------------------------------------------------
+
+ bool hasHwcLayer(int32_t hwcId) {
+ if (mHwcLayers.count(hwcId) == 0) {
+ return false;
+ }
+ if (mHwcLayers[hwcId].layer->isAbandoned()) {
+ ALOGI("Erasing abandoned layer %s on %d", mName.string(), hwcId);
+ mHwcLayers.erase(hwcId);
+ return false;
+ }
+ return true;
+ }
+
+ std::shared_ptr<HWC2::Layer> getHwcLayer(int32_t hwcId) {
+ if (mHwcLayers.count(hwcId) == 0) {
+ return nullptr;
+ }
+ return mHwcLayers[hwcId].layer;
+ }
+
+ void setHwcLayer(int32_t hwcId, std::shared_ptr<HWC2::Layer>&& layer) {
+ if (layer) {
+ mHwcLayers[hwcId].layer = layer;
+ } else {
+ mHwcLayers.erase(hwcId);
+ }
+ }
+
+#endif
// -----------------------------------------------------------------------
void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const;
@@ -474,6 +539,23 @@
// The texture used to draw the layer in GLES composition mode
mutable Texture mTexture;
+#ifdef USE_HWC2
+ // HWC items, accessed from the main thread
+ struct HWCInfo {
+ HWCInfo()
+ : layer(),
+ forceClientComposition(false),
+ compositionType(HWC2::Composition::Invalid),
+ clearClientTarget(false) {}
+
+ std::shared_ptr<HWC2::Layer> layer;
+ bool forceClientComposition;
+ HWC2::Composition compositionType;
+ bool clearClientTarget;
+ };
+ std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+#endif
+
// page-flip thread (currently main thread)
bool mProtectedByApp; // application requires protected path to external sink
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp
index 14aa328..4d5b3db 100644
--- a/services/surfaceflinger/LayerDim.cpp
+++ b/services/surfaceflinger/LayerDim.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// #define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "LayerDim"
+
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
diff --git a/services/surfaceflinger/RenderEngine/GLES10RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES10RenderEngine.cpp
index 9a47568..579affb 100644
--- a/services/surfaceflinger/RenderEngine/GLES10RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES10RenderEngine.cpp
@@ -28,13 +28,25 @@
}
void GLES10RenderEngine::setupLayerBlending(
+#ifdef USE_HWC2
+ bool premultipliedAlpha, bool opaque, float alpha) {
+#else
bool premultipliedAlpha, bool opaque, int alpha) {
+#endif
// OpenGL ES 1.0 doesn't support texture combiners.
// This path doesn't properly handle opaque layers that have non-opaque
// alpha values. The alpha channel will be copied into the framebuffer or
// screenshot, so if the framebuffer or screenshot is blended on top of
// something else, whatever is below the window will incorrectly show
// through.
+#ifdef USE_HWC2
+ if (CC_UNLIKELY(alpha < 1.0f)) {
+ if (premultipliedAlpha) {
+ glColor4f(alpha, alpha, alpha, alpha);
+ } else {
+ glColor4f(1.0f, 1.0f, 1.0f, alpha);
+ }
+#else
if (CC_UNLIKELY(alpha < 0xFF)) {
GLfloat floatAlpha = alpha * (1.0f / 255.0f);
if (premultipliedAlpha) {
@@ -42,12 +54,17 @@
} else {
glColor4f(1.0f, 1.0f, 1.0f, floatAlpha);
}
+#endif
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
} else {
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
+#ifdef USE_HWC2
+ if (alpha < 1.0f || !opaque) {
+#else
if (alpha < 0xFF || !opaque) {
+#endif
glEnable(GL_BLEND);
glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA);
diff --git a/services/surfaceflinger/RenderEngine/GLES10RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES10RenderEngine.h
index f9c7c04..61abd6a 100644
--- a/services/surfaceflinger/RenderEngine/GLES10RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES10RenderEngine.h
@@ -30,7 +30,12 @@
class GLES10RenderEngine : public GLES11RenderEngine {
virtual ~GLES10RenderEngine();
protected:
+#ifdef USE_HWC2
+ virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
+ float alpha) override;
+#else
virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha);
+#endif
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
index 1a9f59b..847cdb3 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.cpp
@@ -107,20 +107,33 @@
glMatrixMode(GL_MODELVIEW);
}
+#ifdef USE_HWC2
+void GLES11RenderEngine::setupLayerBlending(bool premultipliedAlpha,
+ bool opaque, float alpha) {
+#else
void GLES11RenderEngine::setupLayerBlending(
bool premultipliedAlpha, bool opaque, int alpha) {
+#endif
GLenum combineRGB;
GLenum combineAlpha;
GLenum src0Alpha;
GLfloat envColor[4];
+#ifdef USE_HWC2
+ if (CC_UNLIKELY(alpha < 1.0f)) {
+#else
if (CC_UNLIKELY(alpha < 0xFF)) {
+#endif
// Cv = premultiplied ? Cs*alpha : Cs
// Av = !opaque ? As*alpha : As
combineRGB = premultipliedAlpha ? GL_MODULATE : GL_REPLACE;
combineAlpha = !opaque ? GL_MODULATE : GL_REPLACE;
src0Alpha = GL_CONSTANT;
+#ifdef USE_HWC2
+ envColor[0] = alpha;
+#else
envColor[0] = alpha * (1.0f / 255.0f);
+#endif
} else {
// Cv = Cs
// Av = opaque ? 1.0 : As
@@ -152,7 +165,11 @@
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor);
}
+#ifdef USE_HWC2
+ if (alpha < 1.0f || !opaque) {
+#else
if (alpha < 0xFF || !opaque) {
+#endif
glEnable(GL_BLEND);
glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA);
@@ -161,16 +178,28 @@
}
}
+#ifdef USE_HWC2
+void GLES11RenderEngine::setupDimLayerBlending(float alpha) {
+#else
void GLES11RenderEngine::setupDimLayerBlending(int alpha) {
+#endif
glDisable(GL_TEXTURE_EXTERNAL_OES);
glDisable(GL_TEXTURE_2D);
+#ifdef USE_HWC2
+ if (alpha == 1.0f) {
+#else
if (alpha == 0xFF) {
+#endif
glDisable(GL_BLEND);
} else {
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
+#ifdef USE_HWC2
+ glColor4f(0, 0, 0, alpha);
+#else
glColor4f(0, 0, 0, alpha/255.0f);
+#endif
}
void GLES11RenderEngine::setupLayerTexturing(const Texture& texture) {
diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
index 08de646..4cd968d 100644
--- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
@@ -51,9 +51,17 @@
virtual void dump(String8& result);
virtual void setViewportAndProjection(size_t vpw, size_t vph,
- Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation);
- virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha);
+ Rect sourceCrop, size_t hwh, bool yswap,
+ Transform::orientation_flags rotation);
+#ifdef USE_HWC2
+ virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
+ float alpha) override;
+ virtual void setupDimLayerBlending(float alpha) override;
+#else
+ virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
+ int alpha);
virtual void setupDimLayerBlending(int alpha);
+#endif
virtual void setupLayerTexturing(const Texture& texture);
virtual void setupLayerBlackedOut();
virtual void setupFillWithColor(float r, float g, float b, float a) ;
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 1fabaf5..406e611 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -117,14 +117,25 @@
mVpHeight = vph;
}
+#ifdef USE_HWC2
+void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha,
+ bool opaque, float alpha) {
+#else
void GLES20RenderEngine::setupLayerBlending(
bool premultipliedAlpha, bool opaque, int alpha) {
+#endif
mState.setPremultipliedAlpha(premultipliedAlpha);
mState.setOpaque(opaque);
+#ifdef USE_HWC2
+ mState.setPlaneAlpha(alpha);
+
+ if (alpha < 1.0f || !opaque) {
+#else
mState.setPlaneAlpha(alpha / 255.0f);
if (alpha < 0xFF || !opaque) {
+#endif
glEnable(GL_BLEND);
glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} else {
@@ -132,14 +143,26 @@
}
}
+#ifdef USE_HWC2
+void GLES20RenderEngine::setupDimLayerBlending(float alpha) {
+#else
void GLES20RenderEngine::setupDimLayerBlending(int alpha) {
+#endif
mState.setPlaneAlpha(1.0f);
mState.setPremultipliedAlpha(true);
mState.setOpaque(false);
+#ifdef USE_HWC2
+ mState.setColor(0, 0, 0, alpha);
+#else
mState.setColor(0, 0, 0, alpha/255.0f);
+#endif
mState.disableTexture();
+#ifdef USE_HWC2
+ if (alpha == 1.0f) {
+#else
if (alpha == 0xFF) {
+#endif
glDisable(GL_BLEND);
} else {
glEnable(GL_BLEND);
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 819356a..7c3f9b5 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -66,9 +66,17 @@
virtual void dump(String8& result);
virtual void setViewportAndProjection(size_t vpw, size_t vph,
- Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation);
- virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha);
+ Rect sourceCrop, size_t hwh, bool yswap,
+ Transform::orientation_flags rotation);
+#ifdef USE_HWC2
+ virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
+ float alpha) override;
+ virtual void setupDimLayerBlending(float alpha) override;
+#else
+ virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
+ int alpha);
virtual void setupDimLayerBlending(int alpha);
+#endif
virtual void setupLayerTexturing(const Texture& texture);
virtual void setupLayerBlackedOut();
virtual void setupFillWithColor(float r, float g, float b, float a);
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 31a961e..9cc1ed7 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -93,8 +93,13 @@
virtual void checkErrors() const;
virtual void setViewportAndProjection(size_t vpw, size_t vph,
Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation) = 0;
+#ifdef USE_HWC2
+ virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) = 0;
+ virtual void setupDimLayerBlending(float alpha) = 0;
+#else
virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha) = 0;
virtual void setupDimLayerBlending(int alpha) = 0;
+#endif
virtual void setupLayerTexturing(const Texture& texture) = 0;
virtual void setupLayerBlackedOut() = 0;
virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 737cc82..0a3534f 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>
@@ -134,8 +135,9 @@
mRepaintEverything(0),
mRenderEngine(NULL),
mBootTime(systemTime()),
+ mBuiltinDisplays(),
mVisibleRegionsDirty(false),
- mHwWorkListDirty(false),
+ mGeometryInvalid(false),
mAnimCompositionPending(false),
mDebugRegion(0),
mDebugDDMS(0),
@@ -263,6 +265,7 @@
}
void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) {
+ ALOGV("createBuiltinDisplayLocked(%d)", type);
ALOGW_IF(mBuiltinDisplays[type],
"Overwriting display token for display type %d", type);
mBuiltinDisplays[type] = new BBinder();
@@ -442,80 +445,48 @@
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
+ { // Autolock scope
+ Mutex::Autolock _l(mStateLock);
+
+ // initialize EGL for the default display
+ mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(mEGLDisplay, NULL, NULL);
+
+ // start the EventThread
+ sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
+ vsyncPhaseOffsetNs, true, "app");
+ mEventThread = new EventThread(vsyncSrc);
+ sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
+ sfVsyncPhaseOffsetNs, true, "sf");
+ mSFEventThread = new EventThread(sfVsyncSrc);
+ mEventQueue.setEventThread(mSFEventThread);
+
+ // Get a RenderEngine for the given display / config (can't fail)
+ mRenderEngine = RenderEngine::create(mEGLDisplay,
+ HAL_PIXEL_FORMAT_RGBA_8888);
+ }
+
+ // Drop the state lock while we initialize the hardware composer. We drop
+ // the lock because on creation, it will call back into SurfaceFlinger to
+ // initialize the primary display.
+ mHwc = new HWComposer(this);
+ mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));
+
Mutex::Autolock _l(mStateLock);
- // initialize EGL for the default display
- mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(mEGLDisplay, NULL, NULL);
-
- // start the EventThread
- sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
- vsyncPhaseOffsetNs, true, "app");
- mEventThread = new EventThread(vsyncSrc);
- sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
- sfVsyncPhaseOffsetNs, true, "sf");
- mSFEventThread = new EventThread(sfVsyncSrc);
- mEventQueue.setEventThread(mSFEventThread);
-
- // Initialize the H/W composer object. There may or may not be an
- // actual hardware composer underneath.
- mHwc = new HWComposer(this,
- *static_cast<HWComposer::EventHandler *>(this));
-
- // get a RenderEngine for the given display / config (can't fail)
- mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID());
-
// retrieve the EGL context that was selected/created
mEGLContext = mRenderEngine->getEGLContext();
LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
"couldn't create EGLContext");
- // initialize our non-virtual displays
- for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
- DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
- // set-up the displays that are already connected
- if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
- // All non-virtual displays are currently considered secure.
- bool isSecure = true;
- createBuiltinDisplayLocked(type);
- wp<IBinder> token = mBuiltinDisplays[i];
-
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer,
- new GraphicBufferAlloc());
-
- sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
- consumer);
- int32_t hwcId = allocateHwcDisplayId(type);
- sp<DisplayDevice> hw = new DisplayDevice(this,
- type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
- fbs, producer,
- mRenderEngine->getEGLConfig());
- if (i > DisplayDevice::DISPLAY_PRIMARY) {
- // FIXME: currently we don't get blank/unblank requests
- // for displays other than the main display, so we always
- // assume a connected display is unblanked.
- ALOGD("marking display %zu as acquired/unblanked", i);
- hw->setPowerMode(HWC_POWER_MODE_NORMAL);
- }
- mDisplays.add(token, hw);
- }
- }
-
- // make the GLContext current so that we can create textures when creating Layers
- // (which may happens before we render something)
+ // make the GLContext current so that we can create textures when creating
+ // Layers (which may happens before we render something)
getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
mEventControlThread = new EventControlThread(this);
mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
- // set a fake vsync period if there is no HWComposer
- if (mHwc->initCheck() != NO_ERROR) {
- mPrimaryDispSync.setPeriod(16666667);
- }
-
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -524,11 +495,8 @@
// start boot animation
startBootAnim();
-}
-int32_t SurfaceFlinger::allocateHwcDisplayId(DisplayDevice::DisplayType type) {
- return (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) ?
- type : mHwc->allocateDisplayId();
+ ALOGV("Done initializing");
}
void SurfaceFlinger::startBootAnim() {
@@ -594,14 +562,11 @@
configs->clear();
- const Vector<HWComposer::DisplayConfig>& hwConfigs =
- getHwComposer().getConfigs(type);
- for (size_t c = 0; c < hwConfigs.size(); ++c) {
- const HWComposer::DisplayConfig& hwConfig = hwConfigs[c];
+ for (const auto& hwConfig : getHwComposer().getConfigs(type)) {
DisplayInfo info = DisplayInfo();
- float xdpi = hwConfig.xdpi;
- float ydpi = hwConfig.ydpi;
+ float xdpi = hwConfig->getDpiX();
+ float ydpi = hwConfig->getDpiY();
if (type == DisplayDevice::DISPLAY_PRIMARY) {
// The density of the device is provided by a build property
@@ -629,13 +594,15 @@
info.orientation = 0;
}
- info.w = hwConfig.width;
- info.h = hwConfig.height;
+ info.w = hwConfig->getWidth();
+ info.h = hwConfig->getHeight();
info.xdpi = xdpi;
info.ydpi = ydpi;
- info.fps = float(1e9 / hwConfig.refresh);
+ info.fps = 1e9 / hwConfig->getVsyncPeriod();
info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
- info.colorTransform = hwConfig.colorTransform;
+
+ // TODO: Hook this back up
+ info.colorTransform = 0;
// This is how far in advance a buffer must be queued for
// presentation at a given time. If you want a buffer to appear
@@ -649,8 +616,8 @@
//
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
- info.presentationDeadline =
- hwConfig.refresh - SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000;
+ info.presentationDeadline = hwConfig->getVsyncPeriod() -
+ SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000;
// All non-virtual displays are currently considered secure.
info.secure = true;
@@ -812,8 +779,8 @@
return;
}
- const nsecs_t period =
- getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+ const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const nsecs_t period = activeConfig->getVsyncPeriod();
mPrimaryDispSync.reset();
mPrimaryDispSync.setPeriod(period);
@@ -839,7 +806,7 @@
}
}
-void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
+void SurfaceFlinger::onVSyncReceived(int32_t type, nsecs_t timestamp) {
bool needsHwVsync = false;
{ // Scope for the lock
@@ -856,19 +823,34 @@
}
}
-void SurfaceFlinger::onHotplugReceived(int type, bool connected) {
- if (mEventThread == NULL) {
- // This is a temporary workaround for b/7145521. A non-null pointer
- // does not mean EventThread has finished initializing, so this
- // is not a correct fix.
- ALOGW("WARNING: EventThread not started, ignoring hotplug");
- return;
- }
+void SurfaceFlinger::onHotplugReceived(int32_t disp, bool connected) {
+ ALOGV("onHotplugReceived(%d, %s)", disp, connected ? "true" : "false");
+ if (disp == DisplayDevice::DISPLAY_PRIMARY) {
+ Mutex::Autolock lock(mStateLock);
- if (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+ // All non-virtual displays are currently considered secure.
+ bool isSecure = true;
+
+ int32_t type = DisplayDevice::DISPLAY_PRIMARY;
+ createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
+ wp<IBinder> token = mBuiltinDisplays[type];
+
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer,
+ new GraphicBufferAlloc());
+
+ sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc,
+ DisplayDevice::DISPLAY_PRIMARY, consumer);
+ sp<DisplayDevice> hw = new DisplayDevice(this,
+ DisplayDevice::DISPLAY_PRIMARY, disp, isSecure, token, fbs,
+ producer, mRenderEngine->getEGLConfig());
+ mDisplays.add(token, hw);
+ } else {
+ auto type = DisplayDevice::DISPLAY_EXTERNAL;
Mutex::Autolock _l(mStateLock);
if (connected) {
- createBuiltinDisplayLocked((DisplayDevice::DisplayType)type);
+ createBuiltinDisplayLocked(type);
} else {
mCurrentState.displays.removeItem(mBuiltinDisplays[type]);
mBuiltinDisplays[type].clear();
@@ -879,9 +861,10 @@
}
}
-void SurfaceFlinger::eventControl(int disp, int event, int enabled) {
+void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
ATRACE_CALL();
- getHwComposer().eventControl(disp, event, enabled);
+ getHwComposer().setVsyncEnabled(disp,
+ enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
}
void SurfaceFlinger::onMessageReceived(int32_t what) {
@@ -950,6 +933,12 @@
postComposition();
}
+ // Release any buffers which were replaced this frame
+ for (auto& layer : mLayersWithQueuedFrames) {
+ layer->releasePendingBuffer();
+ }
+ mLayersWithQueuedFrames.clear();
+
previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0);
}
@@ -974,7 +963,6 @@
RenderEngine& engine(getRenderEngine());
engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1);
- hw->compositionComplete();
hw->swapBuffers(getHwComposer());
}
}
@@ -986,15 +974,18 @@
usleep(mDebugRegion * 1000);
}
- HWComposer& hwc(getHwComposer());
- if (hwc.initCheck() == NO_ERROR) {
- status_t err = hwc.prepare();
- ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
+ for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
+ status_t result = mDisplays[displayId]->prepareFrame(*mHwc);
+ ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:"
+ " %d (%s)", displayId, result, strerror(-result));
}
}
void SurfaceFlinger::preComposition()
{
+ ATRACE_CALL();
+ ALOGV("preComposition");
+
bool needExtraInvalidate = false;
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
@@ -1010,14 +1001,16 @@
void SurfaceFlinger::postComposition()
{
+ ATRACE_CALL();
+ ALOGV("postComposition");
+
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
layers[i]->onPostComposition();
}
- const HWComposer& hwc = getHwComposer();
- sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
+ sp<Fence> presentFence = mHwc->getRetireFence(HWC_DISPLAY_PRIMARY);
if (presentFence->isValid()) {
if (mPrimaryDispSync.addPresentFence(presentFence)) {
@@ -1042,7 +1035,8 @@
} else {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
- nsecs_t presentTime = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+ nsecs_t presentTime =
+ mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
mAnimFrameTracker.setActualPresentTime(presentTime);
}
mAnimFrameTracker.advanceFrame();
@@ -1070,6 +1064,9 @@
}
void SurfaceFlinger::rebuildLayerStacks() {
+ ATRACE_CALL();
+ ALOGV("rebuildLayerStacks");
+
// rebuild the visible layer list per screen
if (CC_UNLIKELY(mVisibleRegionsDirty)) {
ATRACE_CALL();
@@ -1080,37 +1077,47 @@
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
Region opaqueRegion;
Region dirtyRegion;
- Vector< sp<Layer> > layersSortedByZ;
- const sp<DisplayDevice>& hw(mDisplays[dpy]);
- const Transform& tr(hw->getTransform());
- const Rect bounds(hw->getBounds());
- if (hw->isDisplayOn()) {
+ Vector<sp<Layer>> layersSortedByZ;
+ const sp<DisplayDevice>& displayDevice(mDisplays[dpy]);
+ const Transform& tr(displayDevice->getTransform());
+ const Rect bounds(displayDevice->getBounds());
+ if (displayDevice->isDisplayOn()) {
SurfaceFlinger::computeVisibleRegions(layers,
- hw->getLayerStack(), dirtyRegion, opaqueRegion);
+ displayDevice->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()) {
+ if (s.layerStack == displayDevice->getLayerStack()) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
if (!drawRegion.isEmpty()) {
layersSortedByZ.add(layer);
+ } else {
+ // Clear out the HWC layer if this layer was
+ // previously visible, but no longer is
+ layer->setHwcLayer(displayDevice->getHwcDisplayId(),
+ nullptr);
}
}
}
}
- hw->setVisibleLayersSortedByZ(layersSortedByZ);
- hw->undefinedRegion.set(bounds);
- hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
- hw->dirtyRegion.orSelf(dirtyRegion);
+ displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
+ displayDevice->undefinedRegion.set(bounds);
+ displayDevice->undefinedRegion.subtractSelf(
+ tr.transform(opaqueRegion));
+ displayDevice->dirtyRegion.orSelf(dirtyRegion);
}
}
}
void SurfaceFlinger::setUpHWComposer() {
+ ATRACE_CALL();
+ ALOGV("setUpHWComposer");
+
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
@@ -1140,86 +1147,61 @@
}
}
- HWComposer& hwc(getHwComposer());
- if (hwc.initCheck() == NO_ERROR) {
- // build the h/w work list
- if (CC_UNLIKELY(mHwWorkListDirty)) {
- mHwWorkListDirty = false;
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- const int32_t id = hw->getHwcDisplayId();
- if (id >= 0) {
- const Vector< sp<Layer> >& currentLayers(
- hw->getVisibleLayersSortedByZ());
- const size_t count = currentLayers.size();
- if (hwc.createWorkList(id, count) == NO_ERROR) {
- HWComposer::LayerListIterator cur = hwc.begin(id);
- const HWComposer::LayerListIterator end = hwc.end(id);
- for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
- const sp<Layer>& layer(currentLayers[i]);
- layer->setGeometry(hw, *cur);
- if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) {
- cur->setSkip(true);
- }
+ // build the h/w work list
+ if (CC_UNLIKELY(mGeometryInvalid)) {
+ mGeometryInvalid = false;
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ sp<const DisplayDevice> displayDevice(mDisplays[dpy]);
+ const auto hwcId = displayDevice->getHwcDisplayId();
+ if (hwcId >= 0) {
+ const Vector<sp<Layer>>& currentLayers(
+ displayDevice->getVisibleLayersSortedByZ());
+ bool foundLayerWithoutHwc = false;
+ for (auto& layer : currentLayers) {
+ if (!layer->hasHwcLayer(hwcId)) {
+ auto hwcLayer = mHwc->createLayer(hwcId);
+ if (hwcLayer) {
+ layer->setHwcLayer(hwcId, std::move(hwcLayer));
+ } else {
+ layer->forceClientComposition(hwcId);
+ foundLayerWithoutHwc = true;
+ continue;
}
}
- }
- }
- }
- // set the per-frame data
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- const int32_t id = hw->getHwcDisplayId();
- if (id >= 0) {
- const Vector< sp<Layer> >& currentLayers(
- hw->getVisibleLayersSortedByZ());
- const size_t count = currentLayers.size();
- HWComposer::LayerListIterator cur = hwc.begin(id);
- const HWComposer::LayerListIterator end = hwc.end(id);
- for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
- /*
- * update the per-frame h/w composer data for each layer
- * and build the transparent region of the FB
- */
- const sp<Layer>& layer(currentLayers[i]);
- layer->setPerFrameData(hw, *cur);
- }
- }
- }
-
- // If possible, attempt to use the cursor overlay on each display.
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- const int32_t id = hw->getHwcDisplayId();
- if (id >= 0) {
- const Vector< sp<Layer> >& currentLayers(
- hw->getVisibleLayersSortedByZ());
- const size_t count = currentLayers.size();
- HWComposer::LayerListIterator cur = hwc.begin(id);
- const HWComposer::LayerListIterator end = hwc.end(id);
- for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
- const sp<Layer>& layer(currentLayers[i]);
- if (layer->isPotentialCursor()) {
- cur->setIsCursorLayerHint();
- break;
+ layer->setGeometry(displayDevice);
+ if (mDebugDisableHWC || mDebugRegion || mDaltonize ||
+ mHasColorMatrix) {
+ layer->forceClientComposition(hwcId);
}
}
}
}
+ }
- status_t err = hwc.prepare();
- ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
-
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- hw->prepareFrame(hwc);
+ // Set the per-frame data
+ for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
+ auto& displayDevice = mDisplays[displayId];
+ const auto hwcId = displayDevice->getHwcDisplayId();
+ if (hwcId < 0) {
+ continue;
}
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ layer->setPerFrameData(displayDevice);
+ }
+ }
+
+ for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
+ status_t result = mDisplays[displayId]->prepareFrame(*mHwc);
+ ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:"
+ " %d (%s)", displayId, result, strerror(-result));
}
}
void SurfaceFlinger::doComposition() {
ATRACE_CALL();
+ ALOGV("doComposition");
+
const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& hw(mDisplays[dpy]);
@@ -1234,8 +1216,6 @@
hw->flip(hw->swapRegion);
hw->swapRegion.clear();
}
- // inform the h/w that we're done compositing
- hw->compositionComplete();
}
postFramebuffer();
}
@@ -1243,43 +1223,37 @@
void SurfaceFlinger::postFramebuffer()
{
ATRACE_CALL();
+ ALOGV("postFramebuffer");
const nsecs_t now = systemTime();
mDebugInSwapBuffers = now;
- HWComposer& hwc(getHwComposer());
- if (hwc.initCheck() == NO_ERROR) {
- if (!hwc.supportsFramebufferTarget()) {
- // EGL spec says:
- // "surface must be bound to the calling thread's current context,
- // for the current rendering API."
- getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
+ for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
+ auto& displayDevice = mDisplays[displayId];
+ const auto hwcId = displayDevice->getHwcDisplayId();
+ if (hwcId >= 0) {
+ mHwc->commit(hwcId);
}
- hwc.commit();
- }
-
- // make the default display current because the VirtualDisplayDevice code cannot
- // deal with dequeueBuffer() being called outside of the composition loop; however
- // the code below can call glFlush() which is allowed (and does in some case) call
- // dequeueBuffer().
- getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
-
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- const Vector< sp<Layer> >& currentLayers(hw->getVisibleLayersSortedByZ());
- hw->onSwapBuffersCompleted(hwc);
- const size_t count = currentLayers.size();
- int32_t id = hw->getHwcDisplayId();
- if (id >=0 && hwc.initCheck() == NO_ERROR) {
- HWComposer::LayerListIterator cur = hwc.begin(id);
- const HWComposer::LayerListIterator end = hwc.end(id);
- for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
- currentLayers[i]->onLayerDisplayed(hw, &*cur);
+ if (displayId == 0) {
+ // Make the default display current because the VirtualDisplayDevice
+ // code cannot deal with dequeueBuffer() being called outside of the
+ // composition loop; however the code below can call glFlush() which
+ // is allowed to (and does in some case) call dequeueBuffer().
+ displayDevice->makeCurrent(mEGLDisplay, mEGLContext);
+ }
+ displayDevice->onSwapBuffersCompleted();
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ sp<Fence> releaseFence = Fence::NO_FENCE;
+ if (layer->getCompositionType(hwcId) == HWC2::Composition::Client) {
+ releaseFence = displayDevice->getClientTargetAcquireFence();
+ } else {
+ auto hwcLayer = layer->getHwcLayer(hwcId);
+ releaseFence = mHwc->getLayerReleaseFence(hwcId, hwcLayer);
}
- } else {
- for (size_t i = 0; i < count; i++) {
- currentLayers[i]->onLayerDisplayed(hw, NULL);
- }
+ layer->onLayerDisplayed(releaseFence);
+ }
+ if (hwcId >= 0) {
+ mHwc->clearReleaseFences(hwcId);
}
}
@@ -1439,7 +1413,7 @@
BufferQueue::createBufferQueue(&bqProducer, &bqConsumer,
new GraphicBufferAlloc());
- int32_t hwcDisplayId = -1;
+ int32_t hwcId = -1;
if (state.isVirtualDisplay()) {
// Virtual displays without a surface are dormant:
// they have external state (layer stack, projection,
@@ -1456,15 +1430,14 @@
NATIVE_WINDOW_HEIGHT, &height);
ALOGE_IF(status != NO_ERROR,
"Unable to query height (%d)", status);
- if (MAX_VIRTUAL_DISPLAY_DIMENSION == 0 ||
- (width <= MAX_VIRTUAL_DISPLAY_DIMENSION &&
- height <= MAX_VIRTUAL_DISPLAY_DIMENSION)) {
- hwcDisplayId = allocateHwcDisplayId(state.type);
- }
- sp<VirtualDisplaySurface> vds = new VirtualDisplaySurface(
- *mHwc, hwcDisplayId, state.surface,
- bqProducer, bqConsumer, state.displayName);
+ mHwc->allocateVirtualDisplay(width, height,
+ &hwcId);
+
+ sp<VirtualDisplaySurface> vds =
+ new VirtualDisplaySurface(*mHwc,
+ hwcId, state.surface, bqProducer,
+ bqConsumer, state.displayName);
dispSurface = vds;
producer = vds;
@@ -1474,33 +1447,30 @@
"adding a supported display, but rendering "
"surface is provided (%p), ignoring it",
state.surface.get());
- hwcDisplayId = allocateHwcDisplayId(state.type);
- // for supported (by hwc) displays we provide our
- // own rendering surface
- dispSurface = new FramebufferSurface(*mHwc, state.type,
- bqConsumer);
- producer = bqProducer;
+ if (state.type == DisplayDevice::DISPLAY_EXTERNAL) {
+ hwcId = DisplayDevice::DISPLAY_EXTERNAL;
+ dispSurface = new FramebufferSurface(*mHwc,
+ DisplayDevice::DISPLAY_EXTERNAL,
+ bqConsumer);
+ producer = bqProducer;
+ } else {
+ ALOGE("Attempted to add non-external non-virtual"
+ " display");
+ }
}
const wp<IBinder>& display(curr.keyAt(i));
if (dispSurface != NULL) {
sp<DisplayDevice> hw = new DisplayDevice(this,
- state.type, hwcDisplayId,
- mHwc->getFormat(hwcDisplayId), state.isSecure,
- display, dispSurface, producer,
+ state.type, hwcId, state.isSecure, display,
+ dispSurface, producer,
mRenderEngine->getEGLConfig());
hw->setLayerStack(state.layerStack);
hw->setProjection(state.orientation,
state.viewport, state.frame);
hw->setDisplayName(state.displayName);
mDisplays.add(display, hw);
- if (state.isVirtualDisplay()) {
- if (hwcDisplayId >= 0) {
- mHwc->setVirtualDisplayProperties(hwcDisplayId,
- hw->getWidth(), hw->getHeight(),
- hw->getFormat());
- }
- } else {
+ if (!state.isVirtualDisplay()) {
mEventThread->onHotplugReceived(state.type, true);
}
}
@@ -1607,26 +1577,14 @@
void SurfaceFlinger::updateCursorAsync()
{
- HWComposer& hwc(getHwComposer());
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- sp<const DisplayDevice> hw(mDisplays[dpy]);
- const int32_t id = hw->getHwcDisplayId();
- if (id < 0) {
+ for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
+ auto& displayDevice = mDisplays[displayId];
+ if (displayDevice->getHwcDisplayId() < 0) {
continue;
}
- const Vector< sp<Layer> >& currentLayers(
- hw->getVisibleLayersSortedByZ());
- const size_t count = currentLayers.size();
- HWComposer::LayerListIterator cur = hwc.begin(id);
- const HWComposer::LayerListIterator end = hwc.end(id);
- for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
- if (cur->getCompositionType() != HWC_CURSOR_OVERLAY) {
- continue;
- }
- const sp<Layer>& layer(currentLayers[i]);
- Rect cursorPos = layer->getPosition(hw);
- hwc.setCursorPositionAsync(id, cursorPos);
- break;
+
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ layer->updateCursorPosition(displayDevice);
}
}
}
@@ -1656,6 +1614,7 @@
Region& outDirtyRegion, Region& outOpaqueRegion)
{
ATRACE_CALL();
+ ALOGV("computeVisibleRegions");
Region aboveOpaqueLayers;
Region aboveCoveredLayers;
@@ -1729,7 +1688,7 @@
// compute the opaque region
const int32_t layerOrientation = s.transform.getOrientation();
- if (s.alpha==255 && !translucent &&
+ if (s.alpha == 1.0f && !translucent &&
((layerOrientation & Transform::ROT_INVALID) == false)) {
// the opaque region is the layer's footprint
opaqueRegion = visibleRegion;
@@ -1802,6 +1761,8 @@
bool SurfaceFlinger::handlePageFlip()
{
+ ALOGV("handlePageFlip");
+
Region dirtyRegion;
bool visibleRegions = false;
@@ -1817,13 +1778,12 @@
// 3.) Layer 1 is latched.
// Display is now waiting on Layer 1's frame, which is behind layer 0's
// second frame. But layer 0's second frame could be waiting on display.
- Vector<Layer*> layersWithQueuedFrames;
for (size_t i = 0, count = layers.size(); i<count ; i++) {
const sp<Layer>& layer(layers[i]);
if (layer->hasQueuedFrame()) {
frameQueued = true;
if (layer->shouldPresentNow(mPrimaryDispSync)) {
- layersWithQueuedFrames.push_back(layer.get());
+ mLayersWithQueuedFrames.push_back(layer.get());
} else {
layer->useEmptyDamage();
}
@@ -1831,8 +1791,7 @@
layer->useEmptyDamage();
}
}
- for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
- Layer* layer = layersWithQueuedFrames[i];
+ for (auto& layer : mLayersWithQueuedFrames) {
const Region dirty(layer->latchBuffer(visibleRegions));
layer->useSurfaceDamage();
const Layer::State& s(layer->getDrawingState());
@@ -1844,17 +1803,17 @@
// If we will need to wake up at some time in the future to deal with a
// queued frame that shouldn't be displayed during this vsync period, wake
// up during the next vsync period to check again.
- if (frameQueued && layersWithQueuedFrames.empty()) {
+ if (frameQueued && mLayersWithQueuedFrames.empty()) {
signalLayerUpdate();
}
// Only continue with the refresh if there is actually new work to do
- return !layersWithQueuedFrames.empty();
+ return !mLayersWithQueuedFrames.empty();
}
void SurfaceFlinger::invalidateHwcGeometry()
{
- mHwWorkListDirty = true;
+ mGeometryInvalid = true;
}
@@ -1867,9 +1826,12 @@
// 2) There is work to be done (the dirty region isn't empty)
bool isHwcDisplay = hw->getHwcDisplayId() >= 0;
if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
+ ALOGV("Skipping display composition");
return;
}
+ ALOGV("doDisplayComposition");
+
Region dirtyRegion(inDirtyRegion);
// compute the invalid region
@@ -1915,19 +1877,19 @@
hw->swapBuffers(getHwComposer());
}
-bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
+bool SurfaceFlinger::doComposeSurfaces(
+ const sp<const DisplayDevice>& displayDevice, const Region& dirty)
{
- RenderEngine& engine(getRenderEngine());
- const int32_t id = hw->getHwcDisplayId();
- HWComposer& hwc(getHwComposer());
- HWComposer::LayerListIterator cur = hwc.begin(id);
- const HWComposer::LayerListIterator end = hwc.end(id);
+ ALOGV("doComposeSurfaces");
- bool hasGlesComposition = hwc.hasGlesComposition(id);
- if (hasGlesComposition) {
- if (!hw->makeCurrent(mEGLDisplay, mEGLContext)) {
+ const auto hwcId = displayDevice->getHwcDisplayId();
+ bool hasClientComposition = mHwc->hasClientComposition(hwcId);
+ if (hasClientComposition) {
+ ALOGV("hasClientComposition");
+
+ if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) {
ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
- hw->getDisplayName().string());
+ displayDevice->getDisplayName().string());
eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) {
ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
@@ -1936,25 +1898,25 @@
}
// Never touch the framebuffer if we don't have any framebuffer layers
- const bool hasHwcComposition = hwc.hasHwcComposition(id);
- if (hasHwcComposition) {
+ const bool hasDeviceComposition = mHwc->hasDeviceComposition(hwcId);
+ if (hasDeviceComposition) {
// when using overlays, we assume a fully transparent framebuffer
// NOTE: we could reduce how much we need to clear, for instance
// remove where there are opaque FB layers. however, on some
// GPUs doing a "clean slate" clear might be more efficient.
// We'll revisit later if needed.
- engine.clearWithColor(0, 0, 0, 0);
+ mRenderEngine->clearWithColor(0, 0, 0, 0);
} else {
// we start with the whole screen area
- const Region bounds(hw->getBounds());
+ const Region bounds(displayDevice->getBounds());
// we remove the scissor part
// we're left with the letterbox region
// (common case is that letterbox ends-up being empty)
- const Region letterbox(bounds.subtract(hw->getScissor()));
+ const Region letterbox(bounds.subtract(displayDevice->getScissor()));
// compute the area to clear
- Region region(hw->undefinedRegion.merge(letterbox));
+ Region region(displayDevice->undefinedRegion.merge(letterbox));
// but limit it to the dirty region
region.andSelf(dirty);
@@ -1962,24 +1924,24 @@
// screen is already cleared here
if (!region.isEmpty()) {
// can happen with SurfaceView
- drawWormhole(hw, region);
+ drawWormhole(displayDevice, region);
}
}
- if (hw->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) {
+ if (displayDevice->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) {
// just to be on the safe side, we don't set the
// scissor on the main display. It should never be needed
// anyways (though in theory it could since the API allows it).
- const Rect& bounds(hw->getBounds());
- const Rect& scissor(hw->getScissor());
+ const Rect& bounds(displayDevice->getBounds());
+ const Rect& scissor(displayDevice->getScissor());
if (scissor != bounds) {
// scissor doesn't match the screen's dimensions, so we
// need to clear everything outside of it and enable
// the GL scissor so we don't draw anything where we shouldn't
// enable scissor for this frame
- const uint32_t height = hw->getHeight();
- engine.setScissor(scissor.left, height - scissor.bottom,
+ const uint32_t height = displayDevice->getHeight();
+ mRenderEngine->setScissor(scissor.left, height - scissor.bottom,
scissor.getWidth(), scissor.getHeight());
}
}
@@ -1989,57 +1951,57 @@
* and then, render the layers targeted at the framebuffer
*/
- const Vector< sp<Layer> >& layers(hw->getVisibleLayersSortedByZ());
- const size_t count = layers.size();
- const Transform& tr = hw->getTransform();
- if (cur != end) {
+ ALOGV("Rendering client layers");
+ const Transform& displayTransform = displayDevice->getTransform();
+ if (hwcId >= 0) {
// we're using h/w composer
- for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) {
- const sp<Layer>& layer(layers[i]);
- const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
+ bool firstLayer = true;
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ const Region clip(dirty.intersect(
+ displayTransform.transform(layer->visibleRegion)));
+ ALOGV("Layer: %s", layer->getName().string());
+ ALOGV(" Composition type: %s",
+ to_string(layer->getCompositionType(hwcId)).c_str());
if (!clip.isEmpty()) {
- switch (cur->getCompositionType()) {
- case HWC_CURSOR_OVERLAY:
- case HWC_OVERLAY: {
+ switch (layer->getCompositionType(hwcId)) {
+ case HWC2::Composition::Cursor:
+ case HWC2::Composition::Device:
+ case HWC2::Composition::SolidColor: {
const Layer::State& state(layer->getDrawingState());
- if ((cur->getHints() & HWC_HINT_CLEAR_FB)
- && i
- && layer->isOpaque(state) && (state.alpha == 0xFF)
- && hasGlesComposition) {
+ if (layer->getClearClientTarget(hwcId) && !firstLayer &&
+ layer->isOpaque(state) && (state.alpha == 1.0f)
+ && hasClientComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
- layer->clearWithOpenGL(hw, clip);
+ layer->clearWithOpenGL(displayDevice, clip);
}
break;
}
- case HWC_FRAMEBUFFER: {
- layer->draw(hw, clip);
+ case HWC2::Composition::Client: {
+ layer->draw(displayDevice, clip);
break;
}
- case HWC_FRAMEBUFFER_TARGET: {
- // this should not happen as the iterator shouldn't
- // let us get there.
- ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%zu)", i);
+ default:
break;
- }
}
+ } else {
+ ALOGV(" Skipping for empty clip");
}
- layer->setAcquireFence(hw, *cur);
+ firstLayer = false;
}
} else {
// we're not using h/w composer
- for (size_t i=0 ; i<count ; ++i) {
- const sp<Layer>& layer(layers[i]);
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
const Region clip(dirty.intersect(
- tr.transform(layer->visibleRegion)));
+ displayTransform.transform(layer->visibleRegion)));
if (!clip.isEmpty()) {
- layer->draw(hw, clip);
+ layer->draw(displayDevice, clip);
}
}
}
// disable scissor at the end of the frame
- engine.disableScissor();
+ mRenderEngine->disableScissor();
return true;
}
@@ -2255,7 +2217,7 @@
}
}
if (what & layer_state_t::eAlphaChanged) {
- if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
+ if (layer->setAlpha(s.alpha))
flags |= eTraversalNeeded;
}
if (what & layer_state_t::eMatrixChanged) {
@@ -2423,8 +2385,8 @@
setTransactionState(state, displays, 0);
setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL);
- const nsecs_t period =
- getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+ const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
}
@@ -2611,8 +2573,8 @@
index++;
}
- const nsecs_t period =
- getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+ const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+ const nsecs_t period = activeConfig->getVsyncPeriod();
result.appendFormat("%" PRId64 "\n", period);
if (name.isEmpty()) {
@@ -2734,13 +2696,15 @@
result.append(SyncFeatures::getInstance().toString());
result.append("\n");
+ const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+
colorizer.bold(result);
result.append("DispSync configuration: ");
colorizer.reset(result);
result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, "
"present offset %d ns (refresh %" PRId64 " ns)",
- vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS,
- mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
+ vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
+ PRESENT_TIME_OFFSET_FROM_VSYNC_NS, activeConfig->getVsyncPeriod());
result.append("\n");
// Dump static screen stats
@@ -2808,9 +2772,9 @@
mLastSwapBufferTime/1000.0,
mLastTransactionTime/1000.0,
mTransactionFlags,
- 1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY),
- hwc.getDpiX(HWC_DISPLAY_PRIMARY),
- hwc.getDpiY(HWC_DISPLAY_PRIMARY),
+ 1e9 / activeConfig->getVsyncPeriod(),
+ activeConfig->getDpiX(),
+ activeConfig->getDpiY(),
!mGpuToCpuSupported);
result.appendFormat(" eglSwapBuffers time: %f us\n",
@@ -2830,10 +2794,10 @@
colorizer.bold(result);
result.append("h/w composer state:\n");
colorizer.reset(result);
- result.appendFormat(" h/w composer %s and %s\n",
- hwc.initCheck()==NO_ERROR ? "present" : "not present",
- (mDebugDisableHWC || mDebugRegion || mDaltonize
- || mHasColorMatrix) ? "disabled" : "enabled");
+ bool hwcDisabled = mDebugDisableHWC || mDebugRegion || mDaltonize ||
+ mHasColorMatrix;
+ result.appendFormat(" h/w composer %s\n",
+ hwcDisabled ? "disabled" : "enabled");
hwc.dump(result);
/*
@@ -3338,8 +3302,6 @@
}
}
- // compositionComplete is needed for older driver
- hw->compositionComplete();
hw->setViewportAndProjection();
}
@@ -3516,7 +3478,7 @@
const bool visible = (state.layerStack == hw->getLayerStack())
&& (state.z >= minLayerZ && state.z <= maxLayerZ)
&& (layer->isVisible());
- ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%x",
+ ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
visible ? '+' : '-',
i, layer->getName().string(), state.layerStack, state.z,
layer->isVisible(), state.flags, state.alpha);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4101a70..7d6f139 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -119,7 +119,11 @@
// enable/disable h/w composer event
// TODO: this should be made accessible only to EventThread
+#ifdef USE_HWC2
+ void setVsyncEnabled(int disp, int enabled);
+#else
void eventControl(int disp, int event, int enabled);
+#endif
// called on the main thread by MessageQueue when an internal message
// is received
@@ -361,8 +365,9 @@
// region of all screens presenting this layer stack.
void invalidateLayerStack(uint32_t layerStack, const Region& dirty);
- // allocate a h/w composer display id
+#ifndef USE_HWC2
int32_t allocateHwcDisplayId(DisplayDevice::DisplayType type);
+#endif
/* ------------------------------------------------------------------------
* H/W composer
@@ -458,8 +463,15 @@
// don't need synchronization
State mDrawingState;
bool mVisibleRegionsDirty;
+#ifndef USE_HWC2
bool mHwWorkListDirty;
+#else
+ bool mGeometryInvalid;
+#endif
bool mAnimCompositionPending;
+#ifdef USE_HWC2
+ std::vector<sp<Layer>> mLayersWithQueuedFrames;
+#endif
// this may only be written from the main thread with mStateLock held
// it may be read from other threads with mStateLock held
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index d3b66e6..4c80fa0 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -87,7 +87,11 @@
}
// Release the previous buffer.
+#ifdef USE_HWC2
+ err = updateAndReleaseLocked(item, &mPendingRelease);
+#else
err = updateAndReleaseLocked(item);
+#endif
if (err != NO_ERROR) {
return err;
}
@@ -183,6 +187,40 @@
return nextRefresh + extraPadding;
}
+#ifdef USE_HWC2
+void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence)
+{
+ if (!mPendingRelease.isPending) {
+ GLConsumer::setReleaseFence(fence);
+ return;
+ }
+ auto currentTexture = mPendingRelease.currentTexture;
+ if (fence->isValid() &&
+ currentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+ status_t result = addReleaseFence(currentTexture,
+ mPendingRelease.graphicBuffer, fence);
+ ALOGE_IF(result != NO_ERROR, "setReleaseFence: failed to add the"
+ " fence: %s (%d)", strerror(-result), result);
+ }
+}
+
+void SurfaceFlingerConsumer::releasePendingBuffer()
+{
+ if (!mPendingRelease.isPending) {
+ ALOGV("Pending buffer already released");
+ return;
+ }
+ ALOGV("Releasing pending buffer");
+ Mutex::Autolock lock(mMutex);
+ status_t result = releaseBufferLocked(mPendingRelease.currentTexture,
+ mPendingRelease.graphicBuffer, mPendingRelease.display,
+ mPendingRelease.fence);
+ ALOGE_IF(result != NO_ERROR, "releasePendingBuffer failed: %s (%d)",
+ strerror(-result), result);
+ mPendingRelease = PendingRelease();
+}
+#endif
+
void SurfaceFlingerConsumer::setContentsChangedListener(
const wp<ContentsChangedListener>& listener) {
setFrameAvailableListener(listener);
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index f3942ab..f40d53e 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -75,6 +75,11 @@
nsecs_t computeExpectedPresent(const DispSync& dispSync);
+#ifdef USE_HWC2
+ virtual void setReleaseFence(const sp<Fence>& fence) override;
+ void releasePendingBuffer();
+#endif
+
private:
virtual void onSidebandStreamChanged();
@@ -87,6 +92,12 @@
// The portion of this surface that has changed since the previous frame
Region mSurfaceDamage;
+
+#ifdef USE_HWC2
+ // A release that is pending on the receipt of a new release fence from
+ // presentDisplay
+ PendingRelease mPendingRelease;
+#endif
};
// ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
new file mode 100644
index 0000000..737cc82
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -0,0 +1,3590 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <math.h>
+#include <dlfcn.h>
+#include <inttypes.h>
+#include <stdatomic.h>
+
+#include <EGL/egl.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/PermissionCache.h>
+
+#include <ui/DisplayInfo.h>
+#include <ui/DisplayStatInfo.h>
+
+#include <gui/BitTube.h>
+#include <gui/BufferQueue.h>
+#include <gui/GuiConfig.h>
+#include <gui/IDisplayEventConnection.h>
+#include <gui/Surface.h>
+#include <gui/GraphicBufferAlloc.h>
+
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+#include <ui/UiConfig.h>
+
+#include <utils/misc.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/StopWatch.h>
+#include <utils/Timers.h>
+#include <utils/Trace.h>
+
+#include <private/android_filesystem_config.h>
+#include <private/gui/SyncFeatures.h>
+
+#include "Client.h"
+#include "clz.h"
+#include "Colorizer.h"
+#include "DdmConnection.h"
+#include "DisplayDevice.h"
+#include "DispSync.h"
+#include "EventControlThread.h"
+#include "EventThread.h"
+#include "Layer.h"
+#include "LayerDim.h"
+#include "SurfaceFlinger.h"
+
+#include "DisplayHardware/FramebufferSurface.h"
+#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/VirtualDisplaySurface.h"
+
+#include "Effects/Daltonizer.h"
+
+#include "RenderEngine/RenderEngine.h"
+#include <cutils/compiler.h>
+
+#define DISPLAY_COUNT 1
+
+/*
+ * DEBUG_SCREENSHOTS: set to true to check that screenshots are not all
+ * black pixels.
+ */
+#define DEBUG_SCREENSHOTS false
+
+EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+
+namespace android {
+
+// This is the phase offset in nanoseconds of the software vsync event
+// relative to the vsync event reported by HWComposer. The software vsync
+// event is when SurfaceFlinger and Choreographer-based applications run each
+// frame.
+//
+// This phase offset allows adjustment of the minimum latency from application
+// wake-up (by Choregographer) time to the time at which the resulting window
+// image is displayed. This value may be either positive (after the HW vsync)
+// or negative (before the HW vsync). Setting it to 0 will result in a
+// minimum latency of two vsync periods because the app and SurfaceFlinger
+// will run just after the HW vsync. Setting it to a positive number will
+// result in the minimum latency being:
+//
+// (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD))
+//
+// Note that reducing this latency makes it more likely for the applications
+// to not have their window content image ready in time. When this happens
+// the latency will end up being an additional vsync period, and animations
+// will hiccup. Therefore, this latency should be tuned somewhat
+// conservatively (or at least with awareness of the trade-off being made).
+static const int64_t vsyncPhaseOffsetNs = VSYNC_EVENT_PHASE_OFFSET_NS;
+
+// This is the phase offset at which SurfaceFlinger's composition runs.
+static const int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS;
+
+// ---------------------------------------------------------------------------
+
+const String16 sHardwareTest("android.permission.HARDWARE_TEST");
+const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
+const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
+const String16 sDump("android.permission.DUMP");
+
+// ---------------------------------------------------------------------------
+
+SurfaceFlinger::SurfaceFlinger()
+ : BnSurfaceComposer(),
+ mTransactionFlags(0),
+ mTransactionPending(false),
+ mAnimTransactionPending(false),
+ mLayersRemoved(false),
+ mRepaintEverything(0),
+ mRenderEngine(NULL),
+ mBootTime(systemTime()),
+ mVisibleRegionsDirty(false),
+ mHwWorkListDirty(false),
+ mAnimCompositionPending(false),
+ mDebugRegion(0),
+ mDebugDDMS(0),
+ mDebugDisableHWC(0),
+ mDebugDisableTransformHint(0),
+ mDebugInSwapBuffers(0),
+ mLastSwapBufferTime(0),
+ mDebugInTransaction(0),
+ mLastTransactionTime(0),
+ mBootFinished(false),
+ mForceFullDamage(false),
+ mPrimaryHWVsyncEnabled(false),
+ mHWVsyncAvailable(false),
+ mDaltonize(false),
+ mHasColorMatrix(false),
+ mHasPoweredOff(false),
+ mFrameBuckets(),
+ mTotalTime(0),
+ mLastSwapTime(0)
+{
+ ALOGI("SurfaceFlinger is starting");
+
+ // debugging stuff...
+ char value[PROPERTY_VALUE_MAX];
+
+ property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
+ mGpuToCpuSupported = !atoi(value);
+
+ property_get("debug.sf.drop_missed_frames", value, "0");
+ mDropMissedFrames = atoi(value);
+
+ property_get("debug.sf.showupdates", value, "0");
+ mDebugRegion = atoi(value);
+
+ property_get("debug.sf.ddms", value, "0");
+ mDebugDDMS = atoi(value);
+ if (mDebugDDMS) {
+ if (!startDdmConnection()) {
+ // start failed, and DDMS debugging not enabled
+ mDebugDDMS = 0;
+ }
+ }
+ ALOGI_IF(mDebugRegion, "showupdates enabled");
+ ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
+}
+
+void SurfaceFlinger::onFirstRef()
+{
+ mEventQueue.init(this);
+}
+
+SurfaceFlinger::~SurfaceFlinger()
+{
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglTerminate(display);
+}
+
+void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
+{
+ // the window manager died on us. prepare its eulogy.
+
+ // restore initial conditions (default device unblank, etc)
+ initializeDisplays();
+
+ // restart the boot-animation
+ startBootAnim();
+}
+
+sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
+{
+ sp<ISurfaceComposerClient> bclient;
+ sp<Client> client(new Client(this));
+ status_t err = client->initCheck();
+ if (err == NO_ERROR) {
+ bclient = client;
+ }
+ return bclient;
+}
+
+sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
+ bool secure)
+{
+ class DisplayToken : public BBinder {
+ sp<SurfaceFlinger> flinger;
+ virtual ~DisplayToken() {
+ // no more references, this display must be terminated
+ Mutex::Autolock _l(flinger->mStateLock);
+ flinger->mCurrentState.displays.removeItem(this);
+ flinger->setTransactionFlags(eDisplayTransactionNeeded);
+ }
+ public:
+ DisplayToken(const sp<SurfaceFlinger>& flinger)
+ : flinger(flinger) {
+ }
+ };
+
+ sp<BBinder> token = new DisplayToken(this);
+
+ Mutex::Autolock _l(mStateLock);
+ DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure);
+ info.displayName = displayName;
+ mCurrentState.displays.add(token, info);
+
+ return token;
+}
+
+void SurfaceFlinger::destroyDisplay(const sp<IBinder>& display) {
+ Mutex::Autolock _l(mStateLock);
+
+ ssize_t idx = mCurrentState.displays.indexOfKey(display);
+ if (idx < 0) {
+ ALOGW("destroyDisplay: invalid display token");
+ return;
+ }
+
+ const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
+ if (!info.isVirtualDisplay()) {
+ ALOGE("destroyDisplay called for non-virtual display");
+ return;
+ }
+
+ mCurrentState.displays.removeItemsAt(idx);
+ setTransactionFlags(eDisplayTransactionNeeded);
+}
+
+void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) {
+ ALOGW_IF(mBuiltinDisplays[type],
+ "Overwriting display token for display type %d", type);
+ mBuiltinDisplays[type] = new BBinder();
+ // All non-virtual displays are currently considered secure.
+ DisplayDeviceState info(type, true);
+ mCurrentState.displays.add(mBuiltinDisplays[type], info);
+}
+
+sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
+ if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+ ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
+ return NULL;
+ }
+ return mBuiltinDisplays[id];
+}
+
+sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
+{
+ sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
+ return gba;
+}
+
+void SurfaceFlinger::bootFinished()
+{
+ const nsecs_t now = systemTime();
+ const nsecs_t duration = now - mBootTime;
+ ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
+ mBootFinished = true;
+
+ // wait patiently for the window manager death
+ const String16 name("window");
+ sp<IBinder> window(defaultServiceManager()->getService(name));
+ if (window != 0) {
+ window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
+ }
+
+ // stop boot animation
+ // formerly we would just kill the process, but we now ask it to exit so it
+ // can choose where to stop the animation.
+ property_set("service.bootanim.exit", "1");
+
+ const int LOGTAG_SF_STOP_BOOTANIM = 60110;
+ LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
+ ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+}
+
+void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
+ class MessageDestroyGLTexture : public MessageBase {
+ RenderEngine& engine;
+ uint32_t texture;
+ public:
+ MessageDestroyGLTexture(RenderEngine& engine, uint32_t texture)
+ : engine(engine), texture(texture) {
+ }
+ virtual bool handler() {
+ engine.deleteTextures(1, &texture);
+ return true;
+ }
+ };
+ postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture));
+}
+
+class DispSyncSource : public VSyncSource, private DispSync::Callback {
+public:
+ DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
+ const char* label) :
+ mValue(0),
+ mTraceVsync(traceVsync),
+ mVsyncOnLabel(String8::format("VsyncOn-%s", label)),
+ mVsyncEventLabel(String8::format("VSYNC-%s", label)),
+ mDispSync(dispSync),
+ mCallbackMutex(),
+ mCallback(),
+ mVsyncMutex(),
+ mPhaseOffset(phaseOffset),
+ mEnabled(false) {}
+
+ virtual ~DispSyncSource() {}
+
+ virtual void setVSyncEnabled(bool enable) {
+ Mutex::Autolock lock(mVsyncMutex);
+ if (enable) {
+ status_t err = mDispSync->addEventListener(mPhaseOffset,
+ static_cast<DispSync::Callback*>(this));
+ if (err != NO_ERROR) {
+ ALOGE("error registering vsync callback: %s (%d)",
+ strerror(-err), err);
+ }
+ //ATRACE_INT(mVsyncOnLabel.string(), 1);
+ } else {
+ status_t err = mDispSync->removeEventListener(
+ static_cast<DispSync::Callback*>(this));
+ if (err != NO_ERROR) {
+ ALOGE("error unregistering vsync callback: %s (%d)",
+ strerror(-err), err);
+ }
+ //ATRACE_INT(mVsyncOnLabel.string(), 0);
+ }
+ mEnabled = enable;
+ }
+
+ virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
+ Mutex::Autolock lock(mCallbackMutex);
+ mCallback = callback;
+ }
+
+ virtual void setPhaseOffset(nsecs_t phaseOffset) {
+ Mutex::Autolock lock(mVsyncMutex);
+
+ // Normalize phaseOffset to [0, period)
+ auto period = mDispSync->getPeriod();
+ phaseOffset %= period;
+ if (phaseOffset < 0) {
+ // If we're here, then phaseOffset is in (-period, 0). After this
+ // operation, it will be in (0, period)
+ phaseOffset += period;
+ }
+ mPhaseOffset = phaseOffset;
+
+ // If we're not enabled, we don't need to mess with the listeners
+ if (!mEnabled) {
+ return;
+ }
+
+ // Remove the listener with the old offset
+ status_t err = mDispSync->removeEventListener(
+ static_cast<DispSync::Callback*>(this));
+ if (err != NO_ERROR) {
+ ALOGE("error unregistering vsync callback: %s (%d)",
+ strerror(-err), err);
+ }
+
+ // Add a listener with the new offset
+ err = mDispSync->addEventListener(mPhaseOffset,
+ static_cast<DispSync::Callback*>(this));
+ if (err != NO_ERROR) {
+ ALOGE("error registering vsync callback: %s (%d)",
+ strerror(-err), err);
+ }
+ }
+
+private:
+ virtual void onDispSyncEvent(nsecs_t when) {
+ sp<VSyncSource::Callback> callback;
+ {
+ Mutex::Autolock lock(mCallbackMutex);
+ callback = mCallback;
+
+ if (mTraceVsync) {
+ mValue = (mValue + 1) % 2;
+ ATRACE_INT(mVsyncEventLabel.string(), mValue);
+ }
+ }
+
+ if (callback != NULL) {
+ callback->onVSyncEvent(when);
+ }
+ }
+
+ int mValue;
+
+ const bool mTraceVsync;
+ const String8 mVsyncOnLabel;
+ const String8 mVsyncEventLabel;
+
+ DispSync* mDispSync;
+
+ Mutex mCallbackMutex; // Protects the following
+ sp<VSyncSource::Callback> mCallback;
+
+ Mutex mVsyncMutex; // Protects the following
+ nsecs_t mPhaseOffset;
+ bool mEnabled;
+};
+
+void SurfaceFlinger::init() {
+ ALOGI( "SurfaceFlinger's main thread ready to run. "
+ "Initializing graphics H/W...");
+
+ Mutex::Autolock _l(mStateLock);
+
+ // initialize EGL for the default display
+ mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ eglInitialize(mEGLDisplay, NULL, NULL);
+
+ // start the EventThread
+ sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
+ vsyncPhaseOffsetNs, true, "app");
+ mEventThread = new EventThread(vsyncSrc);
+ sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
+ sfVsyncPhaseOffsetNs, true, "sf");
+ mSFEventThread = new EventThread(sfVsyncSrc);
+ mEventQueue.setEventThread(mSFEventThread);
+
+ // Initialize the H/W composer object. There may or may not be an
+ // actual hardware composer underneath.
+ mHwc = new HWComposer(this,
+ *static_cast<HWComposer::EventHandler *>(this));
+
+ // get a RenderEngine for the given display / config (can't fail)
+ mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID());
+
+ // retrieve the EGL context that was selected/created
+ mEGLContext = mRenderEngine->getEGLContext();
+
+ LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
+ "couldn't create EGLContext");
+
+ // initialize our non-virtual displays
+ for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
+ DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
+ // set-up the displays that are already connected
+ if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
+ // All non-virtual displays are currently considered secure.
+ bool isSecure = true;
+ createBuiltinDisplayLocked(type);
+ wp<IBinder> token = mBuiltinDisplays[i];
+
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer,
+ new GraphicBufferAlloc());
+
+ sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
+ consumer);
+ int32_t hwcId = allocateHwcDisplayId(type);
+ sp<DisplayDevice> hw = new DisplayDevice(this,
+ type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
+ fbs, producer,
+ mRenderEngine->getEGLConfig());
+ if (i > DisplayDevice::DISPLAY_PRIMARY) {
+ // FIXME: currently we don't get blank/unblank requests
+ // for displays other than the main display, so we always
+ // assume a connected display is unblanked.
+ ALOGD("marking display %zu as acquired/unblanked", i);
+ hw->setPowerMode(HWC_POWER_MODE_NORMAL);
+ }
+ mDisplays.add(token, hw);
+ }
+ }
+
+ // make the GLContext current so that we can create textures when creating Layers
+ // (which may happens before we render something)
+ getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
+
+ mEventControlThread = new EventControlThread(this);
+ mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
+
+ // set a fake vsync period if there is no HWComposer
+ if (mHwc->initCheck() != NO_ERROR) {
+ mPrimaryDispSync.setPeriod(16666667);
+ }
+
+ // initialize our drawing state
+ mDrawingState = mCurrentState;
+
+ // set initial conditions (e.g. unblank default device)
+ initializeDisplays();
+
+ // start boot animation
+ startBootAnim();
+}
+
+int32_t SurfaceFlinger::allocateHwcDisplayId(DisplayDevice::DisplayType type) {
+ return (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) ?
+ type : mHwc->allocateDisplayId();
+}
+
+void SurfaceFlinger::startBootAnim() {
+ // start boot animation
+ property_set("service.bootanim.exit", "0");
+ property_set("ctl.start", "bootanim");
+}
+
+size_t SurfaceFlinger::getMaxTextureSize() const {
+ return mRenderEngine->getMaxTextureSize();
+}
+
+size_t SurfaceFlinger::getMaxViewportDims() const {
+ return mRenderEngine->getMaxViewportDims();
+}
+
+// ----------------------------------------------------------------------------
+
+bool SurfaceFlinger::authenticateSurfaceTexture(
+ const sp<IGraphicBufferProducer>& bufferProducer) const {
+ Mutex::Autolock _l(mStateLock);
+ sp<IBinder> surfaceTextureBinder(IInterface::asBinder(bufferProducer));
+ return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0;
+}
+
+status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
+ Vector<DisplayInfo>* configs) {
+ if ((configs == NULL) || (display.get() == NULL)) {
+ return BAD_VALUE;
+ }
+
+ if (!display.get())
+ return NAME_NOT_FOUND;
+
+ int32_t type = NAME_NOT_FOUND;
+ for (int i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
+ if (display == mBuiltinDisplays[i]) {
+ type = i;
+ break;
+ }
+ }
+
+ if (type < 0) {
+ return type;
+ }
+
+ // TODO: Not sure if display density should handled by SF any longer
+ class Density {
+ static int getDensityFromProperty(char const* propName) {
+ char property[PROPERTY_VALUE_MAX];
+ int density = 0;
+ if (property_get(propName, property, NULL) > 0) {
+ density = atoi(property);
+ }
+ return density;
+ }
+ public:
+ static int getEmuDensity() {
+ return getDensityFromProperty("qemu.sf.lcd_density"); }
+ static int getBuildDensity() {
+ return getDensityFromProperty("ro.sf.lcd_density"); }
+ };
+
+ configs->clear();
+
+ const Vector<HWComposer::DisplayConfig>& hwConfigs =
+ getHwComposer().getConfigs(type);
+ for (size_t c = 0; c < hwConfigs.size(); ++c) {
+ const HWComposer::DisplayConfig& hwConfig = hwConfigs[c];
+ DisplayInfo info = DisplayInfo();
+
+ float xdpi = hwConfig.xdpi;
+ float ydpi = hwConfig.ydpi;
+
+ if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ // The density of the device is provided by a build property
+ float density = Density::getBuildDensity() / 160.0f;
+ if (density == 0) {
+ // the build doesn't provide a density -- this is wrong!
+ // use xdpi instead
+ ALOGE("ro.sf.lcd_density must be defined as a build property");
+ density = xdpi / 160.0f;
+ }
+ if (Density::getEmuDensity()) {
+ // if "qemu.sf.lcd_density" is specified, it overrides everything
+ xdpi = ydpi = density = Density::getEmuDensity();
+ density /= 160.0f;
+ }
+ info.density = density;
+
+ // TODO: this needs to go away (currently needed only by webkit)
+ sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+ info.orientation = hw->getOrientation();
+ } else {
+ // TODO: where should this value come from?
+ static const int TV_DENSITY = 213;
+ info.density = TV_DENSITY / 160.0f;
+ info.orientation = 0;
+ }
+
+ info.w = hwConfig.width;
+ info.h = hwConfig.height;
+ info.xdpi = xdpi;
+ info.ydpi = ydpi;
+ info.fps = float(1e9 / hwConfig.refresh);
+ info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
+ info.colorTransform = hwConfig.colorTransform;
+
+ // This is how far in advance a buffer must be queued for
+ // presentation at a given time. If you want a buffer to appear
+ // on the screen at time N, you must submit the buffer before
+ // (N - presentationDeadline).
+ //
+ // Normally it's one full refresh period (to give SF a chance to
+ // latch the buffer), but this can be reduced by configuring a
+ // DispSync offset. Any additional delays introduced by the hardware
+ // composer or panel must be accounted for here.
+ //
+ // We add an additional 1ms to allow for processing time and
+ // differences between the ideal and actual refresh rate.
+ info.presentationDeadline =
+ hwConfig.refresh - SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000;
+
+ // All non-virtual displays are currently considered secure.
+ info.secure = true;
+
+ configs->push_back(info);
+ }
+
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */,
+ DisplayStatInfo* stats) {
+ if (stats == NULL) {
+ return BAD_VALUE;
+ }
+
+ // FIXME for now we always return stats for the primary display
+ memset(stats, 0, sizeof(*stats));
+ stats->vsyncTime = mPrimaryDispSync.computeNextRefresh(0);
+ stats->vsyncPeriod = mPrimaryDispSync.getPeriod();
+ return NO_ERROR;
+}
+
+int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) {
+ sp<DisplayDevice> device(getDisplayDevice(display));
+ if (device != NULL) {
+ return device->getActiveConfig();
+ }
+ return BAD_VALUE;
+}
+
+void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode) {
+ ALOGD("Set active config mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
+ this);
+ int32_t type = hw->getDisplayType();
+ int currentMode = hw->getActiveConfig();
+
+ if (mode == currentMode) {
+ ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode);
+ return;
+ }
+
+ if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+ ALOGW("Trying to set config for virtual display");
+ return;
+ }
+
+ hw->setActiveConfig(mode);
+ getHwComposer().setActiveConfig(type, mode);
+}
+
+status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) {
+ class MessageSetActiveConfig: public MessageBase {
+ SurfaceFlinger& mFlinger;
+ sp<IBinder> mDisplay;
+ int mMode;
+ public:
+ MessageSetActiveConfig(SurfaceFlinger& flinger, const sp<IBinder>& disp,
+ int mode) :
+ mFlinger(flinger), mDisplay(disp) { mMode = mode; }
+ virtual bool handler() {
+ Vector<DisplayInfo> configs;
+ mFlinger.getDisplayConfigs(mDisplay, &configs);
+ if (mMode < 0 || mMode >= static_cast<int>(configs.size())) {
+ ALOGE("Attempt to set active config = %d for display with %zu configs",
+ mMode, configs.size());
+ }
+ sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
+ if (hw == NULL) {
+ ALOGE("Attempt to set active config = %d for null display %p",
+ mMode, mDisplay.get());
+ } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
+ ALOGW("Attempt to set active config = %d for virtual display",
+ mMode);
+ } else {
+ mFlinger.setActiveConfigInternal(hw, mMode);
+ }
+ return true;
+ }
+ };
+ sp<MessageBase> msg = new MessageSetActiveConfig(*this, display, mode);
+ postMessageSync(msg);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::clearAnimationFrameStats() {
+ Mutex::Autolock _l(mStateLock);
+ mAnimFrameTracker.clearStats();
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const {
+ Mutex::Autolock _l(mStateLock);
+ mAnimFrameTracker.getStats(outStats);
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
+ return mEventThread->createEventConnection();
+}
+
+// ----------------------------------------------------------------------------
+
+void SurfaceFlinger::waitForEvent() {
+ mEventQueue.waitMessage();
+}
+
+void SurfaceFlinger::signalTransaction() {
+ mEventQueue.invalidate();
+}
+
+void SurfaceFlinger::signalLayerUpdate() {
+ mEventQueue.invalidate();
+}
+
+void SurfaceFlinger::signalRefresh() {
+ mEventQueue.refresh();
+}
+
+status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
+ nsecs_t reltime, uint32_t /* flags */) {
+ return mEventQueue.postMessage(msg, reltime);
+}
+
+status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
+ nsecs_t reltime, uint32_t /* flags */) {
+ status_t res = mEventQueue.postMessage(msg, reltime);
+ if (res == NO_ERROR) {
+ msg->wait();
+ }
+ return res;
+}
+
+void SurfaceFlinger::run() {
+ do {
+ waitForEvent();
+ } while (true);
+}
+
+void SurfaceFlinger::enableHardwareVsync() {
+ Mutex::Autolock _l(mHWVsyncLock);
+ if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
+ mPrimaryDispSync.beginResync();
+ //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
+ mEventControlThread->setVsyncEnabled(true);
+ mPrimaryHWVsyncEnabled = true;
+ }
+}
+
+void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) {
+ Mutex::Autolock _l(mHWVsyncLock);
+
+ if (makeAvailable) {
+ mHWVsyncAvailable = true;
+ } else if (!mHWVsyncAvailable) {
+ ALOGE("resyncToHardwareVsync called when HW vsync unavailable");
+ return;
+ }
+
+ const nsecs_t period =
+ getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+
+ mPrimaryDispSync.reset();
+ mPrimaryDispSync.setPeriod(period);
+
+ if (!mPrimaryHWVsyncEnabled) {
+ mPrimaryDispSync.beginResync();
+ //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
+ mEventControlThread->setVsyncEnabled(true);
+ mPrimaryHWVsyncEnabled = true;
+ }
+}
+
+void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) {
+ Mutex::Autolock _l(mHWVsyncLock);
+ if (mPrimaryHWVsyncEnabled) {
+ //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false);
+ mEventControlThread->setVsyncEnabled(false);
+ mPrimaryDispSync.endResync();
+ mPrimaryHWVsyncEnabled = false;
+ }
+ if (makeUnavailable) {
+ mHWVsyncAvailable = false;
+ }
+}
+
+void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
+ bool needsHwVsync = false;
+
+ { // Scope for the lock
+ Mutex::Autolock _l(mHWVsyncLock);
+ if (type == 0 && mPrimaryHWVsyncEnabled) {
+ needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
+ }
+ }
+
+ if (needsHwVsync) {
+ enableHardwareVsync();
+ } else {
+ disableHardwareVsync(false);
+ }
+}
+
+void SurfaceFlinger::onHotplugReceived(int type, bool connected) {
+ if (mEventThread == NULL) {
+ // This is a temporary workaround for b/7145521. A non-null pointer
+ // does not mean EventThread has finished initializing, so this
+ // is not a correct fix.
+ ALOGW("WARNING: EventThread not started, ignoring hotplug");
+ return;
+ }
+
+ if (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+ Mutex::Autolock _l(mStateLock);
+ if (connected) {
+ createBuiltinDisplayLocked((DisplayDevice::DisplayType)type);
+ } else {
+ mCurrentState.displays.removeItem(mBuiltinDisplays[type]);
+ mBuiltinDisplays[type].clear();
+ }
+ setTransactionFlags(eDisplayTransactionNeeded);
+
+ // Defer EventThread notification until SF has updated mDisplays.
+ }
+}
+
+void SurfaceFlinger::eventControl(int disp, int event, int enabled) {
+ ATRACE_CALL();
+ getHwComposer().eventControl(disp, event, enabled);
+}
+
+void SurfaceFlinger::onMessageReceived(int32_t what) {
+ ATRACE_CALL();
+ switch (what) {
+ case MessageQueue::TRANSACTION: {
+ handleMessageTransaction();
+ break;
+ }
+ case MessageQueue::INVALIDATE: {
+ bool refreshNeeded = handleMessageTransaction();
+ refreshNeeded |= handleMessageInvalidate();
+ refreshNeeded |= mRepaintEverything;
+ if (refreshNeeded) {
+ // Signal a refresh if a transaction modified the window state,
+ // a new buffer was latched, or if HWC has requested a full
+ // repaint
+ signalRefresh();
+ }
+ break;
+ }
+ case MessageQueue::REFRESH: {
+ handleMessageRefresh();
+ break;
+ }
+ }
+}
+
+bool SurfaceFlinger::handleMessageTransaction() {
+ uint32_t transactionFlags = peekTransactionFlags(eTransactionMask);
+ if (transactionFlags) {
+ handleTransaction(transactionFlags);
+ return true;
+ }
+ return false;
+}
+
+bool SurfaceFlinger::handleMessageInvalidate() {
+ ATRACE_CALL();
+ return handlePageFlip();
+}
+
+void SurfaceFlinger::handleMessageRefresh() {
+ ATRACE_CALL();
+
+ static nsecs_t previousExpectedPresent = 0;
+ nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
+ static bool previousFrameMissed = false;
+ bool frameMissed = (expectedPresent == previousExpectedPresent);
+ if (frameMissed != previousFrameMissed) {
+ ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
+ }
+ previousFrameMissed = frameMissed;
+
+ if (CC_UNLIKELY(mDropMissedFrames && frameMissed)) {
+ // Latch buffers, but don't send anything to HWC, then signal another
+ // wakeup for the next vsync
+ preComposition();
+ repaintEverything();
+ } else {
+ preComposition();
+ rebuildLayerStacks();
+ setUpHWComposer();
+ doDebugFlashRegions();
+ doComposition();
+ postComposition();
+ }
+
+ previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0);
+}
+
+void SurfaceFlinger::doDebugFlashRegions()
+{
+ // is debugging enabled
+ if (CC_LIKELY(!mDebugRegion))
+ return;
+
+ const bool repaintEverything = mRepaintEverything;
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ const sp<DisplayDevice>& hw(mDisplays[dpy]);
+ if (hw->isDisplayOn()) {
+ // transform the dirty region into this screen's coordinate space
+ const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
+ if (!dirtyRegion.isEmpty()) {
+ // redraw the whole screen
+ doComposeSurfaces(hw, Region(hw->bounds()));
+
+ // and draw the dirty region
+ const int32_t height = hw->getHeight();
+ RenderEngine& engine(getRenderEngine());
+ engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1);
+
+ hw->compositionComplete();
+ hw->swapBuffers(getHwComposer());
+ }
+ }
+ }
+
+ postFramebuffer();
+
+ if (mDebugRegion > 1) {
+ usleep(mDebugRegion * 1000);
+ }
+
+ HWComposer& hwc(getHwComposer());
+ if (hwc.initCheck() == NO_ERROR) {
+ status_t err = hwc.prepare();
+ ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
+ }
+}
+
+void SurfaceFlinger::preComposition()
+{
+ bool needExtraInvalidate = false;
+ const LayerVector& layers(mDrawingState.layersSortedByZ);
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ if (layers[i]->onPreComposition()) {
+ needExtraInvalidate = true;
+ }
+ }
+ if (needExtraInvalidate) {
+ signalLayerUpdate();
+ }
+}
+
+void SurfaceFlinger::postComposition()
+{
+ const LayerVector& layers(mDrawingState.layersSortedByZ);
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ layers[i]->onPostComposition();
+ }
+
+ const HWComposer& hwc = getHwComposer();
+ sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
+
+ if (presentFence->isValid()) {
+ if (mPrimaryDispSync.addPresentFence(presentFence)) {
+ enableHardwareVsync();
+ } else {
+ disableHardwareVsync(false);
+ }
+ }
+
+ const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+ if (kIgnorePresentFences) {
+ if (hw->isDisplayOn()) {
+ enableHardwareVsync();
+ }
+ }
+
+ if (mAnimCompositionPending) {
+ mAnimCompositionPending = false;
+
+ if (presentFence->isValid()) {
+ mAnimFrameTracker.setActualPresentFence(presentFence);
+ } else {
+ // The HWC doesn't support present fences, so use the refresh
+ // timestamp instead.
+ nsecs_t presentTime = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+ mAnimFrameTracker.setActualPresentTime(presentTime);
+ }
+ mAnimFrameTracker.advanceFrame();
+ }
+
+ if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
+ return;
+ }
+
+ nsecs_t currentTime = systemTime();
+ if (mHasPoweredOff) {
+ mHasPoweredOff = false;
+ } else {
+ nsecs_t period = mPrimaryDispSync.getPeriod();
+ nsecs_t elapsedTime = currentTime - mLastSwapTime;
+ size_t numPeriods = static_cast<size_t>(elapsedTime / period);
+ if (numPeriods < NUM_BUCKETS - 1) {
+ mFrameBuckets[numPeriods] += elapsedTime;
+ } else {
+ mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime;
+ }
+ mTotalTime += elapsedTime;
+ }
+ mLastSwapTime = currentTime;
+}
+
+void SurfaceFlinger::rebuildLayerStacks() {
+ // rebuild the visible layer list per screen
+ if (CC_UNLIKELY(mVisibleRegionsDirty)) {
+ ATRACE_CALL();
+ mVisibleRegionsDirty = false;
+ invalidateHwcGeometry();
+
+ const LayerVector& layers(mDrawingState.layersSortedByZ);
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ Region opaqueRegion;
+ Region dirtyRegion;
+ Vector< sp<Layer> > layersSortedByZ;
+ const sp<DisplayDevice>& hw(mDisplays[dpy]);
+ const Transform& tr(hw->getTransform());
+ const Rect bounds(hw->getBounds());
+ if (hw->isDisplayOn()) {
+ SurfaceFlinger::computeVisibleRegions(layers,
+ hw->getLayerStack(), dirtyRegion, opaqueRegion);
+
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Layer>& layer(layers[i]);
+ const Layer::State& s(layer->getDrawingState());
+ if (s.layerStack == hw->getLayerStack()) {
+ Region drawRegion(tr.transform(
+ layer->visibleNonTransparentRegion));
+ drawRegion.andSelf(bounds);
+ if (!drawRegion.isEmpty()) {
+ layersSortedByZ.add(layer);
+ }
+ }
+ }
+ }
+ hw->setVisibleLayersSortedByZ(layersSortedByZ);
+ hw->undefinedRegion.set(bounds);
+ hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
+ hw->dirtyRegion.orSelf(dirtyRegion);
+ }
+ }
+}
+
+void SurfaceFlinger::setUpHWComposer() {
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
+ bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
+ bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
+
+ // If nothing has changed (!dirty), don't recompose.
+ // If something changed, but we don't currently have any visible layers,
+ // and didn't when we last did a composition, then skip it this time.
+ // The second rule does two things:
+ // - When all layers are removed from a display, we'll emit one black
+ // frame, then nothing more until we get new layers.
+ // - When a display is created with a private layer stack, we won't
+ // emit any black frames until a layer is added to the layer stack.
+ bool mustRecompose = dirty && !(empty && wasEmpty);
+
+ ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
+ "dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy,
+ mustRecompose ? "doing" : "skipping",
+ dirty ? "+" : "-",
+ empty ? "+" : "-",
+ wasEmpty ? "+" : "-");
+
+ mDisplays[dpy]->beginFrame(mustRecompose);
+
+ if (mustRecompose) {
+ mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty;
+ }
+ }
+
+ HWComposer& hwc(getHwComposer());
+ if (hwc.initCheck() == NO_ERROR) {
+ // build the h/w work list
+ if (CC_UNLIKELY(mHwWorkListDirty)) {
+ mHwWorkListDirty = false;
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ sp<const DisplayDevice> hw(mDisplays[dpy]);
+ const int32_t id = hw->getHwcDisplayId();
+ if (id >= 0) {
+ const Vector< sp<Layer> >& currentLayers(
+ hw->getVisibleLayersSortedByZ());
+ const size_t count = currentLayers.size();
+ if (hwc.createWorkList(id, count) == NO_ERROR) {
+ HWComposer::LayerListIterator cur = hwc.begin(id);
+ const HWComposer::LayerListIterator end = hwc.end(id);
+ for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
+ const sp<Layer>& layer(currentLayers[i]);
+ layer->setGeometry(hw, *cur);
+ if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) {
+ cur->setSkip(true);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // set the per-frame data
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ sp<const DisplayDevice> hw(mDisplays[dpy]);
+ const int32_t id = hw->getHwcDisplayId();
+ if (id >= 0) {
+ const Vector< sp<Layer> >& currentLayers(
+ hw->getVisibleLayersSortedByZ());
+ const size_t count = currentLayers.size();
+ HWComposer::LayerListIterator cur = hwc.begin(id);
+ const HWComposer::LayerListIterator end = hwc.end(id);
+ for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
+ /*
+ * update the per-frame h/w composer data for each layer
+ * and build the transparent region of the FB
+ */
+ const sp<Layer>& layer(currentLayers[i]);
+ layer->setPerFrameData(hw, *cur);
+ }
+ }
+ }
+
+ // If possible, attempt to use the cursor overlay on each display.
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ sp<const DisplayDevice> hw(mDisplays[dpy]);
+ const int32_t id = hw->getHwcDisplayId();
+ if (id >= 0) {
+ const Vector< sp<Layer> >& currentLayers(
+ hw->getVisibleLayersSortedByZ());
+ const size_t count = currentLayers.size();
+ HWComposer::LayerListIterator cur = hwc.begin(id);
+ const HWComposer::LayerListIterator end = hwc.end(id);
+ for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
+ const sp<Layer>& layer(currentLayers[i]);
+ if (layer->isPotentialCursor()) {
+ cur->setIsCursorLayerHint();
+ break;
+ }
+ }
+ }
+ }
+
+ status_t err = hwc.prepare();
+ ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
+
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ sp<const DisplayDevice> hw(mDisplays[dpy]);
+ hw->prepareFrame(hwc);
+ }
+ }
+}
+
+void SurfaceFlinger::doComposition() {
+ ATRACE_CALL();
+ const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ const sp<DisplayDevice>& hw(mDisplays[dpy]);
+ if (hw->isDisplayOn()) {
+ // transform the dirty region into this screen's coordinate space
+ const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
+
+ // repaint the framebuffer (if needed)
+ doDisplayComposition(hw, dirtyRegion);
+
+ hw->dirtyRegion.clear();
+ hw->flip(hw->swapRegion);
+ hw->swapRegion.clear();
+ }
+ // inform the h/w that we're done compositing
+ hw->compositionComplete();
+ }
+ postFramebuffer();
+}
+
+void SurfaceFlinger::postFramebuffer()
+{
+ ATRACE_CALL();
+
+ const nsecs_t now = systemTime();
+ mDebugInSwapBuffers = now;
+
+ HWComposer& hwc(getHwComposer());
+ if (hwc.initCheck() == NO_ERROR) {
+ if (!hwc.supportsFramebufferTarget()) {
+ // EGL spec says:
+ // "surface must be bound to the calling thread's current context,
+ // for the current rendering API."
+ getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
+ }
+ hwc.commit();
+ }
+
+ // make the default display current because the VirtualDisplayDevice code cannot
+ // deal with dequeueBuffer() being called outside of the composition loop; however
+ // the code below can call glFlush() which is allowed (and does in some case) call
+ // dequeueBuffer().
+ getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
+
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ sp<const DisplayDevice> hw(mDisplays[dpy]);
+ const Vector< sp<Layer> >& currentLayers(hw->getVisibleLayersSortedByZ());
+ hw->onSwapBuffersCompleted(hwc);
+ const size_t count = currentLayers.size();
+ int32_t id = hw->getHwcDisplayId();
+ if (id >=0 && hwc.initCheck() == NO_ERROR) {
+ HWComposer::LayerListIterator cur = hwc.begin(id);
+ const HWComposer::LayerListIterator end = hwc.end(id);
+ for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
+ currentLayers[i]->onLayerDisplayed(hw, &*cur);
+ }
+ } else {
+ for (size_t i = 0; i < count; i++) {
+ currentLayers[i]->onLayerDisplayed(hw, NULL);
+ }
+ }
+ }
+
+ mLastSwapBufferTime = systemTime() - now;
+ mDebugInSwapBuffers = 0;
+
+ uint32_t flipCount = getDefaultDisplayDevice()->getPageFlipCount();
+ if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
+ logFrameStats();
+ }
+}
+
+void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
+{
+ ATRACE_CALL();
+
+ // here we keep a copy of the drawing state (that is the state that's
+ // going to be overwritten by handleTransactionLocked()) outside of
+ // mStateLock so that the side-effects of the State assignment
+ // don't happen with mStateLock held (which can cause deadlocks).
+ State drawingState(mDrawingState);
+
+ Mutex::Autolock _l(mStateLock);
+ const nsecs_t now = systemTime();
+ mDebugInTransaction = now;
+
+ // Here we're guaranteed that some transaction flags are set
+ // so we can call handleTransactionLocked() unconditionally.
+ // We call getTransactionFlags(), which will also clear the flags,
+ // with mStateLock held to guarantee that mCurrentState won't change
+ // until the transaction is committed.
+
+ transactionFlags = getTransactionFlags(eTransactionMask);
+ handleTransactionLocked(transactionFlags);
+
+ mLastTransactionTime = systemTime() - now;
+ mDebugInTransaction = 0;
+ invalidateHwcGeometry();
+ // here the transaction has been committed
+}
+
+void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
+{
+ const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
+ const size_t count = currentLayers.size();
+
+ // Notify all layers of available frames
+ for (size_t i = 0; i < count; ++i) {
+ currentLayers[i]->notifyAvailableFrames();
+ }
+
+ /*
+ * Traversal of the children
+ * (perform the transaction for each of them if needed)
+ */
+
+ if (transactionFlags & eTraversalNeeded) {
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Layer>& layer(currentLayers[i]);
+ uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
+ if (!trFlags) continue;
+
+ const uint32_t flags = layer->doTransaction(0);
+ if (flags & Layer::eVisibleRegion)
+ mVisibleRegionsDirty = true;
+ }
+ }
+
+ /*
+ * Perform display own transactions if needed
+ */
+
+ if (transactionFlags & eDisplayTransactionNeeded) {
+ // here we take advantage of Vector's copy-on-write semantics to
+ // improve performance by skipping the transaction entirely when
+ // know that the lists are identical
+ const KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
+ const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
+ if (!curr.isIdenticalTo(draw)) {
+ mVisibleRegionsDirty = true;
+ const size_t cc = curr.size();
+ size_t dc = draw.size();
+
+ // find the displays that were removed
+ // (ie: in drawing state but not in current state)
+ // also handle displays that changed
+ // (ie: displays that are in both lists)
+ for (size_t i=0 ; i<dc ; i++) {
+ const ssize_t j = curr.indexOfKey(draw.keyAt(i));
+ if (j < 0) {
+ // in drawing state but not in current state
+ if (!draw[i].isMainDisplay()) {
+ // Call makeCurrent() on the primary display so we can
+ // be sure that nothing associated with this display
+ // is current.
+ const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDevice());
+ defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext);
+ sp<DisplayDevice> hw(getDisplayDevice(draw.keyAt(i)));
+ if (hw != NULL)
+ hw->disconnect(getHwComposer());
+ if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
+ mEventThread->onHotplugReceived(draw[i].type, false);
+ mDisplays.removeItem(draw.keyAt(i));
+ } else {
+ ALOGW("trying to remove the main display");
+ }
+ } else {
+ // this display is in both lists. see if something changed.
+ const DisplayDeviceState& state(curr[j]);
+ const wp<IBinder>& display(curr.keyAt(j));
+ const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
+ const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
+ if (state_binder != draw_binder) {
+ // changing the surface is like destroying and
+ // recreating the DisplayDevice, so we just remove it
+ // from the drawing state, so that it get re-added
+ // below.
+ sp<DisplayDevice> hw(getDisplayDevice(display));
+ if (hw != NULL)
+ hw->disconnect(getHwComposer());
+ mDisplays.removeItem(display);
+ mDrawingState.displays.removeItemsAt(i);
+ dc--; i--;
+ // at this point we must loop to the next item
+ continue;
+ }
+
+ const sp<DisplayDevice> disp(getDisplayDevice(display));
+ if (disp != NULL) {
+ if (state.layerStack != draw[i].layerStack) {
+ disp->setLayerStack(state.layerStack);
+ }
+ if ((state.orientation != draw[i].orientation)
+ || (state.viewport != draw[i].viewport)
+ || (state.frame != draw[i].frame))
+ {
+ disp->setProjection(state.orientation,
+ state.viewport, state.frame);
+ }
+ if (state.width != draw[i].width || state.height != draw[i].height) {
+ disp->setDisplaySize(state.width, state.height);
+ }
+ }
+ }
+ }
+
+ // find displays that were added
+ // (ie: in current state but not in drawing state)
+ for (size_t i=0 ; i<cc ; i++) {
+ if (draw.indexOfKey(curr.keyAt(i)) < 0) {
+ const DisplayDeviceState& state(curr[i]);
+
+ sp<DisplaySurface> dispSurface;
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferProducer> bqProducer;
+ sp<IGraphicBufferConsumer> bqConsumer;
+ BufferQueue::createBufferQueue(&bqProducer, &bqConsumer,
+ new GraphicBufferAlloc());
+
+ int32_t hwcDisplayId = -1;
+ if (state.isVirtualDisplay()) {
+ // Virtual displays without a surface are dormant:
+ // they have external state (layer stack, projection,
+ // etc.) but no internal state (i.e. a DisplayDevice).
+ if (state.surface != NULL) {
+
+ int width = 0;
+ int status = state.surface->query(
+ NATIVE_WINDOW_WIDTH, &width);
+ ALOGE_IF(status != NO_ERROR,
+ "Unable to query width (%d)", status);
+ int height = 0;
+ status = state.surface->query(
+ NATIVE_WINDOW_HEIGHT, &height);
+ ALOGE_IF(status != NO_ERROR,
+ "Unable to query height (%d)", status);
+ if (MAX_VIRTUAL_DISPLAY_DIMENSION == 0 ||
+ (width <= MAX_VIRTUAL_DISPLAY_DIMENSION &&
+ height <= MAX_VIRTUAL_DISPLAY_DIMENSION)) {
+ hwcDisplayId = allocateHwcDisplayId(state.type);
+ }
+
+ sp<VirtualDisplaySurface> vds = new VirtualDisplaySurface(
+ *mHwc, hwcDisplayId, state.surface,
+ bqProducer, bqConsumer, state.displayName);
+
+ dispSurface = vds;
+ producer = vds;
+ }
+ } else {
+ ALOGE_IF(state.surface!=NULL,
+ "adding a supported display, but rendering "
+ "surface is provided (%p), ignoring it",
+ state.surface.get());
+ hwcDisplayId = allocateHwcDisplayId(state.type);
+ // for supported (by hwc) displays we provide our
+ // own rendering surface
+ dispSurface = new FramebufferSurface(*mHwc, state.type,
+ bqConsumer);
+ producer = bqProducer;
+ }
+
+ const wp<IBinder>& display(curr.keyAt(i));
+ if (dispSurface != NULL) {
+ sp<DisplayDevice> hw = new DisplayDevice(this,
+ state.type, hwcDisplayId,
+ mHwc->getFormat(hwcDisplayId), state.isSecure,
+ display, dispSurface, producer,
+ mRenderEngine->getEGLConfig());
+ hw->setLayerStack(state.layerStack);
+ hw->setProjection(state.orientation,
+ state.viewport, state.frame);
+ hw->setDisplayName(state.displayName);
+ mDisplays.add(display, hw);
+ if (state.isVirtualDisplay()) {
+ if (hwcDisplayId >= 0) {
+ mHwc->setVirtualDisplayProperties(hwcDisplayId,
+ hw->getWidth(), hw->getHeight(),
+ hw->getFormat());
+ }
+ } else {
+ mEventThread->onHotplugReceived(state.type, true);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) {
+ // The transform hint might have changed for some layers
+ // (either because a display has changed, or because a layer
+ // as changed).
+ //
+ // Walk through all the layers in currentLayers,
+ // and update their transform hint.
+ //
+ // If a layer is visible only on a single display, then that
+ // display is used to calculate the hint, otherwise we use the
+ // default display.
+ //
+ // NOTE: we do this here, rather than in rebuildLayerStacks() so that
+ // the hint is set before we acquire a buffer from the surface texture.
+ //
+ // NOTE: layer transactions have taken place already, so we use their
+ // drawing state. However, SurfaceFlinger's own transaction has not
+ // happened yet, so we must use the current state layer list
+ // (soon to become the drawing state list).
+ //
+ sp<const DisplayDevice> disp;
+ uint32_t currentlayerStack = 0;
+ for (size_t i=0; i<count; i++) {
+ // NOTE: we rely on the fact that layers are sorted by
+ // layerStack first (so we don't have to traverse the list
+ // of displays for every layer).
+ const sp<Layer>& layer(currentLayers[i]);
+ uint32_t layerStack = layer->getDrawingState().layerStack;
+ if (i==0 || currentlayerStack != layerStack) {
+ currentlayerStack = layerStack;
+ // figure out if this layerstack is mirrored
+ // (more than one display) if so, pick the default display,
+ // if not, pick the only display it's on.
+ disp.clear();
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ sp<const DisplayDevice> hw(mDisplays[dpy]);
+ if (hw->getLayerStack() == currentlayerStack) {
+ if (disp == NULL) {
+ disp = hw;
+ } else {
+ disp = NULL;
+ break;
+ }
+ }
+ }
+ }
+ if (disp == NULL) {
+ // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
+ // redraw after transform hint changes. See bug 8508397.
+
+ // could be null when this layer is using a layerStack
+ // that is not visible on any display. Also can occur at
+ // screen off/on times.
+ disp = getDefaultDisplayDevice();
+ }
+ layer->updateTransformHint(disp);
+ }
+ }
+
+
+ /*
+ * Perform our own transaction if needed
+ */
+
+ const LayerVector& layers(mDrawingState.layersSortedByZ);
+ if (currentLayers.size() > layers.size()) {
+ // layers have been added
+ mVisibleRegionsDirty = true;
+ }
+
+ // some layers might have been removed, so
+ // we need to update the regions they're exposing.
+ if (mLayersRemoved) {
+ mLayersRemoved = false;
+ mVisibleRegionsDirty = true;
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Layer>& layer(layers[i]);
+ if (currentLayers.indexOf(layer) < 0) {
+ // this layer is not visible anymore
+ // TODO: we could traverse the tree from front to back and
+ // compute the actual visible region
+ // TODO: we could cache the transformed region
+ const Layer::State& s(layer->getDrawingState());
+ Region visibleReg = s.transform.transform(
+ Region(Rect(s.active.w, s.active.h)));
+ invalidateLayerStack(s.layerStack, visibleReg);
+ }
+ }
+ }
+
+ commitTransaction();
+
+ updateCursorAsync();
+}
+
+void SurfaceFlinger::updateCursorAsync()
+{
+ HWComposer& hwc(getHwComposer());
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ sp<const DisplayDevice> hw(mDisplays[dpy]);
+ const int32_t id = hw->getHwcDisplayId();
+ if (id < 0) {
+ continue;
+ }
+ const Vector< sp<Layer> >& currentLayers(
+ hw->getVisibleLayersSortedByZ());
+ const size_t count = currentLayers.size();
+ HWComposer::LayerListIterator cur = hwc.begin(id);
+ const HWComposer::LayerListIterator end = hwc.end(id);
+ for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
+ if (cur->getCompositionType() != HWC_CURSOR_OVERLAY) {
+ continue;
+ }
+ const sp<Layer>& layer(currentLayers[i]);
+ Rect cursorPos = layer->getPosition(hw);
+ hwc.setCursorPositionAsync(id, cursorPos);
+ break;
+ }
+ }
+}
+
+void SurfaceFlinger::commitTransaction()
+{
+ if (!mLayersPendingRemoval.isEmpty()) {
+ // Notify removed layers now that they can't be drawn from
+ for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) {
+ mLayersPendingRemoval[i]->onRemoved();
+ }
+ mLayersPendingRemoval.clear();
+ }
+
+ // If this transaction is part of a window animation then the next frame
+ // we composite should be considered an animation as well.
+ mAnimCompositionPending = mAnimTransactionPending;
+
+ mDrawingState = mCurrentState;
+ mTransactionPending = false;
+ mAnimTransactionPending = false;
+ mTransactionCV.broadcast();
+}
+
+void SurfaceFlinger::computeVisibleRegions(
+ const LayerVector& currentLayers, uint32_t layerStack,
+ Region& outDirtyRegion, Region& outOpaqueRegion)
+{
+ ATRACE_CALL();
+
+ Region aboveOpaqueLayers;
+ Region aboveCoveredLayers;
+ Region dirty;
+
+ outDirtyRegion.clear();
+
+ size_t i = currentLayers.size();
+ while (i--) {
+ const sp<Layer>& layer = currentLayers[i];
+
+ // start with the whole surface at its current location
+ const Layer::State& s(layer->getDrawingState());
+
+ // only consider the layers on the given layer stack
+ if (s.layerStack != layerStack)
+ continue;
+
+ /*
+ * opaqueRegion: area of a surface that is fully opaque.
+ */
+ Region opaqueRegion;
+
+ /*
+ * visibleRegion: area of a surface that is visible on screen
+ * and not fully transparent. This is essentially the layer's
+ * footprint minus the opaque regions above it.
+ * Areas covered by a translucent surface are considered visible.
+ */
+ Region visibleRegion;
+
+ /*
+ * coveredRegion: area of a surface that is covered by all
+ * visible regions above it (which includes the translucent areas).
+ */
+ Region coveredRegion;
+
+ /*
+ * transparentRegion: area of a surface that is hinted to be completely
+ * transparent. This is only used to tell when the layer has no visible
+ * non-transparent regions and can be removed from the layer list. It
+ * does not affect the visibleRegion of this layer or any layers
+ * beneath it. The hint may not be correct if apps don't respect the
+ * SurfaceView restrictions (which, sadly, some don't).
+ */
+ Region transparentRegion;
+
+
+ // handle hidden surfaces by setting the visible region to empty
+ if (CC_LIKELY(layer->isVisible())) {
+ const bool translucent = !layer->isOpaque(s);
+ Rect bounds(s.transform.transform(layer->computeBounds()));
+ visibleRegion.set(bounds);
+ if (!visibleRegion.isEmpty()) {
+ // Remove the transparent area from the visible region
+ if (translucent) {
+ const Transform tr(s.transform);
+ if (tr.transformed()) {
+ if (tr.preserveRects()) {
+ // transform the transparent region
+ transparentRegion = tr.transform(s.activeTransparentRegion);
+ } else {
+ // transformation too complex, can't do the
+ // transparent region optimization.
+ transparentRegion.clear();
+ }
+ } else {
+ transparentRegion = s.activeTransparentRegion;
+ }
+ }
+
+ // compute the opaque region
+ const int32_t layerOrientation = s.transform.getOrientation();
+ if (s.alpha==255 && !translucent &&
+ ((layerOrientation & Transform::ROT_INVALID) == false)) {
+ // the opaque region is the layer's footprint
+ opaqueRegion = visibleRegion;
+ }
+ }
+ }
+
+ // Clip the covered region to the visible region
+ coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
+
+ // Update aboveCoveredLayers for next (lower) layer
+ aboveCoveredLayers.orSelf(visibleRegion);
+
+ // subtract the opaque region covered by the layers above us
+ visibleRegion.subtractSelf(aboveOpaqueLayers);
+
+ // compute this layer's dirty region
+ if (layer->contentDirty) {
+ // we need to invalidate the whole region
+ dirty = visibleRegion;
+ // as well, as the old visible region
+ dirty.orSelf(layer->visibleRegion);
+ layer->contentDirty = false;
+ } else {
+ /* compute the exposed region:
+ * the exposed region consists of two components:
+ * 1) what's VISIBLE now and was COVERED before
+ * 2) what's EXPOSED now less what was EXPOSED before
+ *
+ * note that (1) is conservative, we start with the whole
+ * visible region but only keep what used to be covered by
+ * something -- which mean it may have been exposed.
+ *
+ * (2) handles areas that were not covered by anything but got
+ * exposed because of a resize.
+ */
+ const Region newExposed = visibleRegion - coveredRegion;
+ const Region oldVisibleRegion = layer->visibleRegion;
+ const Region oldCoveredRegion = layer->coveredRegion;
+ const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
+ dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
+ }
+ dirty.subtractSelf(aboveOpaqueLayers);
+
+ // accumulate to the screen dirty region
+ outDirtyRegion.orSelf(dirty);
+
+ // Update aboveOpaqueLayers for next (lower) layer
+ aboveOpaqueLayers.orSelf(opaqueRegion);
+
+ // Store the visible region in screen space
+ layer->setVisibleRegion(visibleRegion);
+ layer->setCoveredRegion(coveredRegion);
+ layer->setVisibleNonTransparentRegion(
+ visibleRegion.subtract(transparentRegion));
+ }
+
+ outOpaqueRegion = aboveOpaqueLayers;
+}
+
+void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
+ const Region& dirty) {
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ const sp<DisplayDevice>& hw(mDisplays[dpy]);
+ if (hw->getLayerStack() == layerStack) {
+ hw->dirtyRegion.orSelf(dirty);
+ }
+ }
+}
+
+bool SurfaceFlinger::handlePageFlip()
+{
+ Region dirtyRegion;
+
+ bool visibleRegions = false;
+ const LayerVector& layers(mDrawingState.layersSortedByZ);
+ bool frameQueued = false;
+
+ // Store the set of layers that need updates. This set must not change as
+ // buffers are being latched, as this could result in a deadlock.
+ // Example: Two producers share the same command stream and:
+ // 1.) Layer 0 is latched
+ // 2.) Layer 0 gets a new frame
+ // 2.) Layer 1 gets a new frame
+ // 3.) Layer 1 is latched.
+ // Display is now waiting on Layer 1's frame, which is behind layer 0's
+ // second frame. But layer 0's second frame could be waiting on display.
+ Vector<Layer*> layersWithQueuedFrames;
+ for (size_t i = 0, count = layers.size(); i<count ; i++) {
+ const sp<Layer>& layer(layers[i]);
+ if (layer->hasQueuedFrame()) {
+ frameQueued = true;
+ if (layer->shouldPresentNow(mPrimaryDispSync)) {
+ layersWithQueuedFrames.push_back(layer.get());
+ } else {
+ layer->useEmptyDamage();
+ }
+ } else {
+ layer->useEmptyDamage();
+ }
+ }
+ for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
+ Layer* layer = layersWithQueuedFrames[i];
+ const Region dirty(layer->latchBuffer(visibleRegions));
+ layer->useSurfaceDamage();
+ const Layer::State& s(layer->getDrawingState());
+ invalidateLayerStack(s.layerStack, dirty);
+ }
+
+ mVisibleRegionsDirty |= visibleRegions;
+
+ // If we will need to wake up at some time in the future to deal with a
+ // queued frame that shouldn't be displayed during this vsync period, wake
+ // up during the next vsync period to check again.
+ if (frameQueued && layersWithQueuedFrames.empty()) {
+ signalLayerUpdate();
+ }
+
+ // Only continue with the refresh if there is actually new work to do
+ return !layersWithQueuedFrames.empty();
+}
+
+void SurfaceFlinger::invalidateHwcGeometry()
+{
+ mHwWorkListDirty = true;
+}
+
+
+void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
+ const Region& inDirtyRegion)
+{
+ // We only need to actually compose the display if:
+ // 1) It is being handled by hardware composer, which may need this to
+ // keep its virtual display state machine in sync, or
+ // 2) There is work to be done (the dirty region isn't empty)
+ bool isHwcDisplay = hw->getHwcDisplayId() >= 0;
+ if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
+ return;
+ }
+
+ Region dirtyRegion(inDirtyRegion);
+
+ // compute the invalid region
+ hw->swapRegion.orSelf(dirtyRegion);
+
+ uint32_t flags = hw->getFlags();
+ if (flags & DisplayDevice::SWAP_RECTANGLE) {
+ // we can redraw only what's dirty, but since SWAP_RECTANGLE only
+ // takes a rectangle, we must make sure to update that whole
+ // rectangle in that case
+ dirtyRegion.set(hw->swapRegion.bounds());
+ } else {
+ if (flags & DisplayDevice::PARTIAL_UPDATES) {
+ // We need to redraw the rectangle that will be updated
+ // (pushed to the framebuffer).
+ // This is needed because PARTIAL_UPDATES only takes one
+ // rectangle instead of a region (see DisplayDevice::flip())
+ dirtyRegion.set(hw->swapRegion.bounds());
+ } else {
+ // we need to redraw everything (the whole screen)
+ dirtyRegion.set(hw->bounds());
+ hw->swapRegion = dirtyRegion;
+ }
+ }
+
+ if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) {
+ if (!doComposeSurfaces(hw, dirtyRegion)) return;
+ } else {
+ RenderEngine& engine(getRenderEngine());
+ mat4 colorMatrix = mColorMatrix;
+ if (mDaltonize) {
+ colorMatrix = colorMatrix * mDaltonizer();
+ }
+ mat4 oldMatrix = engine.setupColorTransform(colorMatrix);
+ doComposeSurfaces(hw, dirtyRegion);
+ engine.setupColorTransform(oldMatrix);
+ }
+
+ // update the swap region and clear the dirty region
+ hw->swapRegion.orSelf(dirtyRegion);
+
+ // swap buffers (presentation)
+ hw->swapBuffers(getHwComposer());
+}
+
+bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
+{
+ RenderEngine& engine(getRenderEngine());
+ const int32_t id = hw->getHwcDisplayId();
+ HWComposer& hwc(getHwComposer());
+ HWComposer::LayerListIterator cur = hwc.begin(id);
+ const HWComposer::LayerListIterator end = hwc.end(id);
+
+ bool hasGlesComposition = hwc.hasGlesComposition(id);
+ if (hasGlesComposition) {
+ if (!hw->makeCurrent(mEGLDisplay, mEGLContext)) {
+ ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
+ hw->getDisplayName().string());
+ eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) {
+ ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
+ }
+ return false;
+ }
+
+ // Never touch the framebuffer if we don't have any framebuffer layers
+ const bool hasHwcComposition = hwc.hasHwcComposition(id);
+ if (hasHwcComposition) {
+ // when using overlays, we assume a fully transparent framebuffer
+ // NOTE: we could reduce how much we need to clear, for instance
+ // remove where there are opaque FB layers. however, on some
+ // GPUs doing a "clean slate" clear might be more efficient.
+ // We'll revisit later if needed.
+ engine.clearWithColor(0, 0, 0, 0);
+ } else {
+ // we start with the whole screen area
+ const Region bounds(hw->getBounds());
+
+ // we remove the scissor part
+ // we're left with the letterbox region
+ // (common case is that letterbox ends-up being empty)
+ const Region letterbox(bounds.subtract(hw->getScissor()));
+
+ // compute the area to clear
+ Region region(hw->undefinedRegion.merge(letterbox));
+
+ // but limit it to the dirty region
+ region.andSelf(dirty);
+
+ // screen is already cleared here
+ if (!region.isEmpty()) {
+ // can happen with SurfaceView
+ drawWormhole(hw, region);
+ }
+ }
+
+ if (hw->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) {
+ // just to be on the safe side, we don't set the
+ // scissor on the main display. It should never be needed
+ // anyways (though in theory it could since the API allows it).
+ const Rect& bounds(hw->getBounds());
+ const Rect& scissor(hw->getScissor());
+ if (scissor != bounds) {
+ // scissor doesn't match the screen's dimensions, so we
+ // need to clear everything outside of it and enable
+ // the GL scissor so we don't draw anything where we shouldn't
+
+ // enable scissor for this frame
+ const uint32_t height = hw->getHeight();
+ engine.setScissor(scissor.left, height - scissor.bottom,
+ scissor.getWidth(), scissor.getHeight());
+ }
+ }
+ }
+
+ /*
+ * and then, render the layers targeted at the framebuffer
+ */
+
+ const Vector< sp<Layer> >& layers(hw->getVisibleLayersSortedByZ());
+ const size_t count = layers.size();
+ const Transform& tr = hw->getTransform();
+ if (cur != end) {
+ // we're using h/w composer
+ for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) {
+ const sp<Layer>& layer(layers[i]);
+ const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
+ if (!clip.isEmpty()) {
+ switch (cur->getCompositionType()) {
+ case HWC_CURSOR_OVERLAY:
+ case HWC_OVERLAY: {
+ const Layer::State& state(layer->getDrawingState());
+ if ((cur->getHints() & HWC_HINT_CLEAR_FB)
+ && i
+ && layer->isOpaque(state) && (state.alpha == 0xFF)
+ && hasGlesComposition) {
+ // never clear the very first layer since we're
+ // guaranteed the FB is already cleared
+ layer->clearWithOpenGL(hw, clip);
+ }
+ break;
+ }
+ case HWC_FRAMEBUFFER: {
+ layer->draw(hw, clip);
+ break;
+ }
+ case HWC_FRAMEBUFFER_TARGET: {
+ // this should not happen as the iterator shouldn't
+ // let us get there.
+ ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%zu)", i);
+ break;
+ }
+ }
+ }
+ layer->setAcquireFence(hw, *cur);
+ }
+ } else {
+ // we're not using h/w composer
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<Layer>& layer(layers[i]);
+ const Region clip(dirty.intersect(
+ tr.transform(layer->visibleRegion)));
+ if (!clip.isEmpty()) {
+ layer->draw(hw, clip);
+ }
+ }
+ }
+
+ // disable scissor at the end of the frame
+ engine.disableScissor();
+ return true;
+}
+
+void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, const Region& region) const {
+ const int32_t height = hw->getHeight();
+ RenderEngine& engine(getRenderEngine());
+ engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
+}
+
+status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
+ const sp<IBinder>& handle,
+ const sp<IGraphicBufferProducer>& gbc,
+ const sp<Layer>& lbc)
+{
+ // add this layer to the current state list
+ {
+ Mutex::Autolock _l(mStateLock);
+ if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) {
+ return NO_MEMORY;
+ }
+ mCurrentState.layersSortedByZ.add(lbc);
+ mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
+ }
+
+ // attach this layer to the client
+ client->attachLayer(handle, lbc);
+
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
+ Mutex::Autolock _l(mStateLock);
+ ssize_t index = mCurrentState.layersSortedByZ.remove(layer);
+ if (index >= 0) {
+ mLayersPendingRemoval.push(layer);
+ mLayersRemoved = true;
+ setTransactionFlags(eTransactionNeeded);
+ return NO_ERROR;
+ }
+ return status_t(index);
+}
+
+uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t /* flags */) {
+ return android_atomic_release_load(&mTransactionFlags);
+}
+
+uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) {
+ return android_atomic_and(~flags, &mTransactionFlags) & flags;
+}
+
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
+ uint32_t old = android_atomic_or(flags, &mTransactionFlags);
+ if ((old & flags)==0) { // wake the server up
+ signalTransaction();
+ }
+ return old;
+}
+
+void SurfaceFlinger::setTransactionState(
+ const Vector<ComposerState>& state,
+ const Vector<DisplayState>& displays,
+ uint32_t flags)
+{
+ ATRACE_CALL();
+ Mutex::Autolock _l(mStateLock);
+ uint32_t transactionFlags = 0;
+
+ if (flags & eAnimation) {
+ // For window updates that are part of an animation we must wait for
+ // previous animation "frames" to be handled.
+ while (mAnimTransactionPending) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ // just in case something goes wrong in SF, return to the
+ // caller after a few seconds.
+ ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out "
+ "waiting for previous animation frame");
+ mAnimTransactionPending = false;
+ break;
+ }
+ }
+ }
+
+ size_t count = displays.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const DisplayState& s(displays[i]);
+ transactionFlags |= setDisplayStateLocked(s);
+ }
+
+ count = state.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const ComposerState& s(state[i]);
+ // Here we need to check that the interface we're given is indeed
+ // one of our own. A malicious client could give us a NULL
+ // IInterface, or one of its own or even one of our own but a
+ // different type. All these situations would cause us to crash.
+ //
+ // NOTE: it would be better to use RTTI as we could directly check
+ // that we have a Client*. however, RTTI is disabled in Android.
+ if (s.client != NULL) {
+ sp<IBinder> binder = IInterface::asBinder(s.client);
+ if (binder != NULL) {
+ String16 desc(binder->getInterfaceDescriptor());
+ if (desc == ISurfaceComposerClient::descriptor) {
+ sp<Client> client( static_cast<Client *>(s.client.get()) );
+ transactionFlags |= setClientStateLocked(client, s.state);
+ }
+ }
+ }
+ }
+
+ if (transactionFlags) {
+ // this triggers the transaction
+ setTransactionFlags(transactionFlags);
+
+ // if this is a synchronous transaction, wait for it to take effect
+ // before returning.
+ if (flags & eSynchronous) {
+ mTransactionPending = true;
+ }
+ if (flags & eAnimation) {
+ mAnimTransactionPending = true;
+ }
+ while (mTransactionPending) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ // just in case something goes wrong in SF, return to the
+ // called after a few seconds.
+ ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
+ mTransactionPending = false;
+ break;
+ }
+ }
+ }
+}
+
+uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s)
+{
+ ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token);
+ if (dpyIdx < 0)
+ return 0;
+
+ uint32_t flags = 0;
+ DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx));
+ if (disp.isValid()) {
+ const uint32_t what = s.what;
+ if (what & DisplayState::eSurfaceChanged) {
+ if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) {
+ disp.surface = s.surface;
+ flags |= eDisplayTransactionNeeded;
+ }
+ }
+ if (what & DisplayState::eLayerStackChanged) {
+ if (disp.layerStack != s.layerStack) {
+ disp.layerStack = s.layerStack;
+ flags |= eDisplayTransactionNeeded;
+ }
+ }
+ if (what & DisplayState::eDisplayProjectionChanged) {
+ if (disp.orientation != s.orientation) {
+ disp.orientation = s.orientation;
+ flags |= eDisplayTransactionNeeded;
+ }
+ if (disp.frame != s.frame) {
+ disp.frame = s.frame;
+ flags |= eDisplayTransactionNeeded;
+ }
+ if (disp.viewport != s.viewport) {
+ disp.viewport = s.viewport;
+ flags |= eDisplayTransactionNeeded;
+ }
+ }
+ if (what & DisplayState::eDisplaySizeChanged) {
+ if (disp.width != s.width) {
+ disp.width = s.width;
+ flags |= eDisplayTransactionNeeded;
+ }
+ if (disp.height != s.height) {
+ disp.height = s.height;
+ flags |= eDisplayTransactionNeeded;
+ }
+ }
+ }
+ return flags;
+}
+
+uint32_t SurfaceFlinger::setClientStateLocked(
+ const sp<Client>& client,
+ const layer_state_t& s)
+{
+ uint32_t flags = 0;
+ sp<Layer> layer(client->getLayerUser(s.surface));
+ if (layer != 0) {
+ const uint32_t what = s.what;
+ if (what & layer_state_t::ePositionChanged) {
+ if (layer->setPosition(s.x, s.y))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eLayerChanged) {
+ // NOTE: index needs to be calculated before we update the state
+ ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+ if (layer->setLayer(s.z) && idx >= 0) {
+ mCurrentState.layersSortedByZ.removeAt(idx);
+ mCurrentState.layersSortedByZ.add(layer);
+ // we need traversal (state changed)
+ // AND transaction (list changed)
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
+ if (what & layer_state_t::eSizeChanged) {
+ if (layer->setSize(s.w, s.h)) {
+ flags |= eTraversalNeeded;
+ }
+ }
+ if (what & layer_state_t::eAlphaChanged) {
+ if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eMatrixChanged) {
+ if (layer->setMatrix(s.matrix))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eTransparentRegionChanged) {
+ if (layer->setTransparentRegionHint(s.transparentRegion))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eFlagsChanged) {
+ if (layer->setFlags(s.flags, s.mask))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eCropChanged) {
+ if (layer->setCrop(s.crop))
+ flags |= eTraversalNeeded;
+ }
+ if (what & layer_state_t::eLayerStackChanged) {
+ // NOTE: index needs to be calculated before we update the state
+ ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+ if (layer->setLayerStack(s.layerStack) && idx >= 0) {
+ mCurrentState.layersSortedByZ.removeAt(idx);
+ mCurrentState.layersSortedByZ.add(layer);
+ // we need traversal (state changed)
+ // AND transaction (list changed)
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
+ if (what & layer_state_t::eDeferTransaction) {
+ layer->deferTransactionUntil(s.handle, s.frameNumber);
+ // We don't trigger a traversal here because if no other state is
+ // changed, we don't want this to cause any more work
+ }
+ }
+ return flags;
+}
+
+status_t SurfaceFlinger::createLayer(
+ const String8& name,
+ const sp<Client>& client,
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
+ sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)
+{
+ //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string());
+ if (int32_t(w|h) < 0) {
+ ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
+ int(w), int(h));
+ return BAD_VALUE;
+ }
+
+ status_t result = NO_ERROR;
+
+ sp<Layer> layer;
+
+ switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
+ case ISurfaceComposerClient::eFXSurfaceNormal:
+ result = createNormalLayer(client,
+ name, w, h, flags, format,
+ handle, gbp, &layer);
+ break;
+ case ISurfaceComposerClient::eFXSurfaceDim:
+ result = createDimLayer(client,
+ name, w, h, flags,
+ handle, gbp, &layer);
+ break;
+ default:
+ result = BAD_VALUE;
+ break;
+ }
+
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ result = addClientLayer(client, *handle, *gbp, layer);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ setTransactionFlags(eTransactionNeeded);
+ return result;
+}
+
+status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
+ sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
+{
+ // initialize the surfaces
+ switch (format) {
+ case PIXEL_FORMAT_TRANSPARENT:
+ case PIXEL_FORMAT_TRANSLUCENT:
+ format = PIXEL_FORMAT_RGBA_8888;
+ break;
+ case PIXEL_FORMAT_OPAQUE:
+ format = PIXEL_FORMAT_RGBX_8888;
+ break;
+ }
+
+ *outLayer = new Layer(this, client, name, w, h, flags);
+ status_t err = (*outLayer)->setBuffers(w, h, format, flags);
+ if (err == NO_ERROR) {
+ *handle = (*outLayer)->getHandle();
+ *gbp = (*outLayer)->getProducer();
+ }
+
+ ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
+ return err;
+}
+
+status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags,
+ sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
+{
+ *outLayer = new LayerDim(this, client, name, w, h, flags);
+ *handle = (*outLayer)->getHandle();
+ *gbp = (*outLayer)->getProducer();
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle)
+{
+ // called by the window manager when it wants to remove a Layer
+ status_t err = NO_ERROR;
+ sp<Layer> l(client->getLayerUser(handle));
+ if (l != NULL) {
+ err = removeLayer(l);
+ ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
+ "error removing layer=%p (%s)", l.get(), strerror(-err));
+ }
+ return err;
+}
+
+status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer)
+{
+ // called by ~LayerCleaner() when all references to the IBinder (handle)
+ // are gone
+ status_t err = NO_ERROR;
+ sp<Layer> l(layer.promote());
+ if (l != NULL) {
+ err = removeLayer(l);
+ ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
+ "error removing layer=%p (%s)", l.get(), strerror(-err));
+ }
+ return err;
+}
+
+// ---------------------------------------------------------------------------
+
+void SurfaceFlinger::onInitializeDisplays() {
+ // reset screen orientation and use primary layer stack
+ Vector<ComposerState> state;
+ Vector<DisplayState> displays;
+ DisplayState d;
+ d.what = DisplayState::eDisplayProjectionChanged |
+ DisplayState::eLayerStackChanged;
+ d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY];
+ d.layerStack = 0;
+ d.orientation = DisplayState::eOrientationDefault;
+ d.frame.makeInvalid();
+ d.viewport.makeInvalid();
+ d.width = 0;
+ d.height = 0;
+ displays.add(d);
+ setTransactionState(state, displays, 0);
+ setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL);
+
+ const nsecs_t period =
+ getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+ mAnimFrameTracker.setDisplayRefreshPeriod(period);
+}
+
+void SurfaceFlinger::initializeDisplays() {
+ class MessageScreenInitialized : public MessageBase {
+ SurfaceFlinger* flinger;
+ public:
+ MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
+ virtual bool handler() {
+ flinger->onInitializeDisplays();
+ return true;
+ }
+ };
+ sp<MessageBase> msg = new MessageScreenInitialized(this);
+ postMessageAsync(msg); // we may be called from main thread, use async message
+}
+
+void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
+ int mode) {
+ ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
+ this);
+ int32_t type = hw->getDisplayType();
+ int currentMode = hw->getPowerMode();
+
+ if (mode == currentMode) {
+ ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode);
+ return;
+ }
+
+ hw->setPowerMode(mode);
+ if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+ ALOGW("Trying to set power mode for virtual display");
+ return;
+ }
+
+ if (currentMode == HWC_POWER_MODE_OFF) {
+ getHwComposer().setPowerMode(type, mode);
+ if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ // FIXME: eventthread only knows about the main display right now
+ mEventThread->onScreenAcquired();
+ resyncToHardwareVsync(true);
+ }
+
+ mVisibleRegionsDirty = true;
+ mHasPoweredOff = true;
+ repaintEverything();
+ } else if (mode == HWC_POWER_MODE_OFF) {
+ if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ disableHardwareVsync(true); // also cancels any in-progress resync
+
+ // FIXME: eventthread only knows about the main display right now
+ mEventThread->onScreenReleased();
+ }
+
+ getHwComposer().setPowerMode(type, mode);
+ mVisibleRegionsDirty = true;
+ // from this point on, SF will stop drawing on this display
+ } else {
+ getHwComposer().setPowerMode(type, mode);
+ }
+}
+
+void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) {
+ class MessageSetPowerMode: public MessageBase {
+ SurfaceFlinger& mFlinger;
+ sp<IBinder> mDisplay;
+ int mMode;
+ public:
+ MessageSetPowerMode(SurfaceFlinger& flinger,
+ const sp<IBinder>& disp, int mode) : mFlinger(flinger),
+ mDisplay(disp) { mMode = mode; }
+ virtual bool handler() {
+ sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
+ if (hw == NULL) {
+ ALOGE("Attempt to set power mode = %d for null display %p",
+ mMode, mDisplay.get());
+ } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
+ ALOGW("Attempt to set power mode = %d for virtual display",
+ mMode);
+ } else {
+ mFlinger.setPowerModeInternal(hw, mMode);
+ }
+ return true;
+ }
+ };
+ sp<MessageBase> msg = new MessageSetPowerMode(*this, display, mode);
+ postMessageSync(msg);
+}
+
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
+{
+ String8 result;
+
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_SHELL) &&
+ !PermissionCache::checkPermission(sDump, pid, uid)) {
+ result.appendFormat("Permission Denial: "
+ "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
+ } else {
+ // Try to get the main lock, but give up after one second
+ // (this would indicate SF is stuck, but we want to be able to
+ // print something in dumpsys).
+ status_t err = mStateLock.timedLock(s2ns(1));
+ bool locked = (err == NO_ERROR);
+ if (!locked) {
+ result.appendFormat(
+ "SurfaceFlinger appears to be unresponsive (%s [%d]), "
+ "dumping anyways (no locks held)\n", strerror(-err), err);
+ }
+
+ bool dumpAll = true;
+ size_t index = 0;
+ size_t numArgs = args.size();
+ if (numArgs) {
+ if ((index < numArgs) &&
+ (args[index] == String16("--list"))) {
+ index++;
+ listLayersLocked(args, index, result);
+ dumpAll = false;
+ }
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--latency"))) {
+ index++;
+ dumpStatsLocked(args, index, result);
+ dumpAll = false;
+ }
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--latency-clear"))) {
+ index++;
+ clearStatsLocked(args, index, result);
+ dumpAll = false;
+ }
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--dispsync"))) {
+ index++;
+ mPrimaryDispSync.dump(result);
+ dumpAll = false;
+ }
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--static-screen"))) {
+ index++;
+ dumpStaticScreenStats(result);
+ dumpAll = false;
+ }
+ }
+
+ if (dumpAll) {
+ dumpAllLocked(args, index, result);
+ }
+
+ if (locked) {
+ mStateLock.unlock();
+ }
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+void SurfaceFlinger::listLayersLocked(const Vector<String16>& /* args */,
+ size_t& /* index */, String8& result) const
+{
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Layer>& layer(currentLayers[i]);
+ result.appendFormat("%s\n", layer->getName().string());
+ }
+}
+
+void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index,
+ String8& result) const
+{
+ String8 name;
+ if (index < args.size()) {
+ name = String8(args[index]);
+ index++;
+ }
+
+ const nsecs_t period =
+ getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+ result.appendFormat("%" PRId64 "\n", period);
+
+ if (name.isEmpty()) {
+ mAnimFrameTracker.dumpStats(result);
+ } else {
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Layer>& layer(currentLayers[i]);
+ if (name == layer->getName()) {
+ layer->dumpFrameStats(result);
+ }
+ }
+ }
+}
+
+void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index,
+ String8& /* result */)
+{
+ String8 name;
+ if (index < args.size()) {
+ name = String8(args[index]);
+ index++;
+ }
+
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Layer>& layer(currentLayers[i]);
+ if (name.isEmpty() || (name == layer->getName())) {
+ layer->clearFrameStats();
+ }
+ }
+
+ mAnimFrameTracker.clearStats();
+}
+
+// This should only be called from the main thread. Otherwise it would need
+// the lock and should use mCurrentState rather than mDrawingState.
+void SurfaceFlinger::logFrameStats() {
+ const LayerVector& drawingLayers = mDrawingState.layersSortedByZ;
+ const size_t count = drawingLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Layer>& layer(drawingLayers[i]);
+ layer->logFrameStats();
+ }
+
+ mAnimFrameTracker.logAndResetStats(String8("<win-anim>"));
+}
+
+/*static*/ void SurfaceFlinger::appendSfConfigString(String8& result)
+{
+ static const char* config =
+ " [sf"
+#ifdef HAS_CONTEXT_PRIORITY
+ " HAS_CONTEXT_PRIORITY"
+#endif
+#ifdef NEVER_DEFAULT_TO_ASYNC_MODE
+ " NEVER_DEFAULT_TO_ASYNC_MODE"
+#endif
+#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
+ " TARGET_DISABLE_TRIPLE_BUFFERING"
+#endif
+ "]";
+ result.append(config);
+}
+
+void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
+{
+ result.appendFormat("Static screen stats:\n");
+ for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) {
+ float bucketTimeSec = mFrameBuckets[b] / 1e9;
+ float percent = 100.0f *
+ static_cast<float>(mFrameBuckets[b]) / mTotalTime;
+ result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n",
+ b + 1, bucketTimeSec, percent);
+ }
+ float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9;
+ float percent = 100.0f *
+ static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime;
+ result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n",
+ NUM_BUCKETS - 1, bucketTimeSec, percent);
+}
+
+void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
+ String8& result) const
+{
+ bool colorize = false;
+ if (index < args.size()
+ && (args[index] == String16("--color"))) {
+ colorize = true;
+ index++;
+ }
+
+ Colorizer colorizer(colorize);
+
+ // figure out if we're stuck somewhere
+ const nsecs_t now = systemTime();
+ const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
+ const nsecs_t inTransaction(mDebugInTransaction);
+ nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
+ nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
+
+ /*
+ * Dump library configuration.
+ */
+
+ colorizer.bold(result);
+ result.append("Build configuration:");
+ colorizer.reset(result);
+ appendSfConfigString(result);
+ appendUiConfigString(result);
+ appendGuiConfigString(result);
+ result.append("\n");
+
+ colorizer.bold(result);
+ result.append("Sync configuration: ");
+ colorizer.reset(result);
+ result.append(SyncFeatures::getInstance().toString());
+ result.append("\n");
+
+ colorizer.bold(result);
+ result.append("DispSync configuration: ");
+ colorizer.reset(result);
+ result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, "
+ "present offset %d ns (refresh %" PRId64 " ns)",
+ vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, PRESENT_TIME_OFFSET_FROM_VSYNC_NS,
+ mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
+ result.append("\n");
+
+ // Dump static screen stats
+ result.append("\n");
+ dumpStaticScreenStats(result);
+ result.append("\n");
+
+ /*
+ * Dump the visible layer list
+ */
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+ colorizer.bold(result);
+ result.appendFormat("Visible layers (count = %zu)\n", count);
+ colorizer.reset(result);
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Layer>& layer(currentLayers[i]);
+ layer->dump(result, colorizer);
+ }
+
+ /*
+ * Dump Display state
+ */
+
+ colorizer.bold(result);
+ result.appendFormat("Displays (%zu entries)\n", mDisplays.size());
+ colorizer.reset(result);
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ const sp<const DisplayDevice>& hw(mDisplays[dpy]);
+ hw->dump(result);
+ }
+
+ /*
+ * Dump SurfaceFlinger global state
+ */
+
+ colorizer.bold(result);
+ result.append("SurfaceFlinger global state:\n");
+ colorizer.reset(result);
+
+ HWComposer& hwc(getHwComposer());
+ sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+
+ colorizer.bold(result);
+ result.appendFormat("EGL implementation : %s\n",
+ eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION));
+ colorizer.reset(result);
+ result.appendFormat("%s\n",
+ eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS));
+
+ mRenderEngine->dump(result);
+
+ hw->undefinedRegion.dump(result, "undefinedRegion");
+ result.appendFormat(" orientation=%d, isDisplayOn=%d\n",
+ hw->getOrientation(), hw->isDisplayOn());
+ result.appendFormat(
+ " last eglSwapBuffers() time: %f us\n"
+ " last transaction time : %f us\n"
+ " transaction-flags : %08x\n"
+ " refresh-rate : %f fps\n"
+ " x-dpi : %f\n"
+ " y-dpi : %f\n"
+ " gpu_to_cpu_unsupported : %d\n"
+ ,
+ mLastSwapBufferTime/1000.0,
+ mLastTransactionTime/1000.0,
+ mTransactionFlags,
+ 1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY),
+ hwc.getDpiX(HWC_DISPLAY_PRIMARY),
+ hwc.getDpiY(HWC_DISPLAY_PRIMARY),
+ !mGpuToCpuSupported);
+
+ result.appendFormat(" eglSwapBuffers time: %f us\n",
+ inSwapBuffersDuration/1000.0);
+
+ result.appendFormat(" transaction time: %f us\n",
+ inTransactionDuration/1000.0);
+
+ /*
+ * VSYNC state
+ */
+ mEventThread->dump(result);
+
+ /*
+ * Dump HWComposer state
+ */
+ colorizer.bold(result);
+ result.append("h/w composer state:\n");
+ colorizer.reset(result);
+ result.appendFormat(" h/w composer %s and %s\n",
+ hwc.initCheck()==NO_ERROR ? "present" : "not present",
+ (mDebugDisableHWC || mDebugRegion || mDaltonize
+ || mHasColorMatrix) ? "disabled" : "enabled");
+ hwc.dump(result);
+
+ /*
+ * Dump gralloc state
+ */
+ const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ alloc.dump(result);
+}
+
+const Vector< sp<Layer> >&
+SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) {
+ // Note: mStateLock is held here
+ wp<IBinder> dpy;
+ for (size_t i=0 ; i<mDisplays.size() ; i++) {
+ if (mDisplays.valueAt(i)->getHwcDisplayId() == id) {
+ dpy = mDisplays.keyAt(i);
+ break;
+ }
+ }
+ if (dpy == NULL) {
+ ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id);
+ // Just use the primary display so we have something to return
+ dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY);
+ }
+ return getDisplayDevice(dpy)->getVisibleLayersSortedByZ();
+}
+
+bool SurfaceFlinger::startDdmConnection()
+{
+ void* libddmconnection_dso =
+ dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW);
+ if (!libddmconnection_dso) {
+ return false;
+ }
+ void (*DdmConnection_start)(const char* name);
+ DdmConnection_start =
+ (decltype(DdmConnection_start))dlsym(libddmconnection_dso, "DdmConnection_start");
+ if (!DdmConnection_start) {
+ dlclose(libddmconnection_dso);
+ return false;
+ }
+ (*DdmConnection_start)(getServiceName());
+ return true;
+}
+
+status_t SurfaceFlinger::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case CREATE_CONNECTION:
+ case CREATE_DISPLAY:
+ case SET_TRANSACTION_STATE:
+ case BOOT_FINISHED:
+ case CLEAR_ANIMATION_FRAME_STATS:
+ case GET_ANIMATION_FRAME_STATS:
+ case SET_POWER_MODE:
+ {
+ // codes that require permission check
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
+ !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
+ ALOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ break;
+ }
+ case CAPTURE_SCREEN:
+ {
+ // codes that require permission check
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_GRAPHICS) &&
+ !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
+ ALOGE("Permission Denial: "
+ "can't read framebuffer pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ break;
+ }
+ }
+
+ status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
+ if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ if (CC_UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ ALOGE("Permission Denial: "
+ "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ int n;
+ switch (code) {
+ case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
+ case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
+ return NO_ERROR;
+ case 1002: // SHOW_UPDATES
+ n = data.readInt32();
+ mDebugRegion = n ? n : (mDebugRegion ? 0 : 1);
+ invalidateHwcGeometry();
+ repaintEverything();
+ return NO_ERROR;
+ case 1004:{ // repaint everything
+ repaintEverything();
+ return NO_ERROR;
+ }
+ case 1005:{ // force transaction
+ setTransactionFlags(
+ eTransactionNeeded|
+ eDisplayTransactionNeeded|
+ eTraversalNeeded);
+ return NO_ERROR;
+ }
+ case 1006:{ // send empty update
+ signalRefresh();
+ return NO_ERROR;
+ }
+ case 1008: // toggle use of hw composer
+ n = data.readInt32();
+ mDebugDisableHWC = n ? 1 : 0;
+ invalidateHwcGeometry();
+ repaintEverything();
+ return NO_ERROR;
+ case 1009: // toggle use of transform hint
+ n = data.readInt32();
+ mDebugDisableTransformHint = n ? 1 : 0;
+ invalidateHwcGeometry();
+ repaintEverything();
+ return NO_ERROR;
+ case 1010: // interrogate.
+ reply->writeInt32(0);
+ reply->writeInt32(0);
+ reply->writeInt32(mDebugRegion);
+ reply->writeInt32(0);
+ reply->writeInt32(mDebugDisableHWC);
+ return NO_ERROR;
+ case 1013: {
+ Mutex::Autolock _l(mStateLock);
+ sp<const DisplayDevice> hw(getDefaultDisplayDevice());
+ reply->writeInt32(hw->getPageFlipCount());
+ return NO_ERROR;
+ }
+ case 1014: {
+ // daltonize
+ n = data.readInt32();
+ switch (n % 10) {
+ case 1: mDaltonizer.setType(Daltonizer::protanomaly); break;
+ case 2: mDaltonizer.setType(Daltonizer::deuteranomaly); break;
+ case 3: mDaltonizer.setType(Daltonizer::tritanomaly); break;
+ }
+ if (n >= 10) {
+ mDaltonizer.setMode(Daltonizer::correction);
+ } else {
+ mDaltonizer.setMode(Daltonizer::simulation);
+ }
+ mDaltonize = n > 0;
+ invalidateHwcGeometry();
+ repaintEverything();
+ return NO_ERROR;
+ }
+ case 1015: {
+ // apply a color matrix
+ n = data.readInt32();
+ mHasColorMatrix = n ? 1 : 0;
+ if (n) {
+ // color matrix is sent as mat3 matrix followed by vec3
+ // offset, then packed into a mat4 where the last row is
+ // the offset and extra values are 0
+ for (size_t i = 0 ; i < 4; i++) {
+ for (size_t j = 0; j < 4; j++) {
+ mColorMatrix[i][j] = data.readFloat();
+ }
+ }
+ } else {
+ mColorMatrix = mat4();
+ }
+ invalidateHwcGeometry();
+ repaintEverything();
+ return NO_ERROR;
+ }
+ // This is an experimental interface
+ // Needs to be shifted to proper binder interface when we productize
+ case 1016: {
+ n = data.readInt32();
+ mPrimaryDispSync.setRefreshSkipCount(n);
+ return NO_ERROR;
+ }
+ case 1017: {
+ n = data.readInt32();
+ mForceFullDamage = static_cast<bool>(n);
+ return NO_ERROR;
+ }
+ case 1018: { // Modify Choreographer's phase offset
+ n = data.readInt32();
+ mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ return NO_ERROR;
+ }
+ case 1019: { // Modify SurfaceFlinger's phase offset
+ n = data.readInt32();
+ mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ return NO_ERROR;
+ }
+ }
+ }
+ return err;
+}
+
+void SurfaceFlinger::repaintEverything() {
+ android_atomic_or(1, &mRepaintEverything);
+ signalTransaction();
+}
+
+// ---------------------------------------------------------------------------
+// Capture screen into an IGraphiBufferProducer
+// ---------------------------------------------------------------------------
+
+/* The code below is here to handle b/8734824
+ *
+ * We create a IGraphicBufferProducer wrapper that forwards all calls
+ * from the surfaceflinger thread to the calling binder thread, where they
+ * are executed. This allows the calling thread in the calling process to be
+ * reused and not depend on having "enough" binder threads to handle the
+ * requests.
+ */
+class GraphicProducerWrapper : public BBinder, public MessageHandler {
+ /* Parts of GraphicProducerWrapper are run on two different threads,
+ * communicating by sending messages via Looper but also by shared member
+ * data. Coherence maintenance is subtle and in places implicit (ugh).
+ *
+ * Don't rely on Looper's sendMessage/handleMessage providing
+ * release/acquire semantics for any data not actually in the Message.
+ * Data going from surfaceflinger to binder threads needs to be
+ * synchronized explicitly.
+ *
+ * Barrier open/wait do provide release/acquire semantics. This provides
+ * implicit synchronization for data coming back from binder to
+ * surfaceflinger threads.
+ */
+
+ sp<IGraphicBufferProducer> impl;
+ sp<Looper> looper;
+ status_t result;
+ bool exitPending;
+ bool exitRequested;
+ Barrier barrier;
+ uint32_t code;
+ Parcel const* data;
+ Parcel* reply;
+
+ enum {
+ MSG_API_CALL,
+ MSG_EXIT
+ };
+
+ /*
+ * Called on surfaceflinger thread. This is called by our "fake"
+ * BpGraphicBufferProducer. We package the data and reply Parcel and
+ * forward them to the binder thread.
+ */
+ virtual status_t transact(uint32_t code,
+ const Parcel& data, Parcel* reply, uint32_t /* flags */) {
+ this->code = code;
+ this->data = &data;
+ this->reply = reply;
+ if (exitPending) {
+ // if we've exited, we run the message synchronously right here.
+ // note (JH): as far as I can tell from looking at the code, this
+ // never actually happens. if it does, i'm not sure if it happens
+ // on the surfaceflinger or binder thread.
+ handleMessage(Message(MSG_API_CALL));
+ } else {
+ barrier.close();
+ // Prevent stores to this->{code, data, reply} from being
+ // reordered later than the construction of Message.
+ atomic_thread_fence(memory_order_release);
+ looper->sendMessage(this, Message(MSG_API_CALL));
+ barrier.wait();
+ }
+ return result;
+ }
+
+ /*
+ * here we run on the binder thread. All we've got to do is
+ * call the real BpGraphicBufferProducer.
+ */
+ virtual void handleMessage(const Message& message) {
+ int what = message.what;
+ // Prevent reads below from happening before the read from Message
+ atomic_thread_fence(memory_order_acquire);
+ if (what == MSG_API_CALL) {
+ result = IInterface::asBinder(impl)->transact(code, data[0], reply);
+ barrier.open();
+ } else if (what == MSG_EXIT) {
+ exitRequested = true;
+ }
+ }
+
+public:
+ GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
+ : impl(impl),
+ looper(new Looper(true)),
+ result(NO_ERROR),
+ exitPending(false),
+ exitRequested(false),
+ code(0),
+ data(NULL),
+ reply(NULL)
+ {}
+
+ // Binder thread
+ status_t waitForResponse() {
+ do {
+ looper->pollOnce(-1);
+ } while (!exitRequested);
+ return result;
+ }
+
+ // Client thread
+ void exit(status_t result) {
+ this->result = result;
+ exitPending = true;
+ // Ensure this->result is visible to the binder thread before it
+ // handles the message.
+ atomic_thread_fence(memory_order_release);
+ looper->sendMessage(this, Message(MSG_EXIT));
+ }
+};
+
+
+status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
+
+ if (CC_UNLIKELY(display == 0))
+ return BAD_VALUE;
+
+ if (CC_UNLIKELY(producer == 0))
+ return BAD_VALUE;
+
+ // if we have secure windows on this display, never allow the screen capture
+ // unless the producer interface is local (i.e.: we can take a screenshot for
+ // ourselves).
+ bool isLocalScreenshot = IInterface::asBinder(producer)->localBinder();
+
+ // Convert to surfaceflinger's internal rotation type.
+ Transform::orientation_flags rotationFlags;
+ switch (rotation) {
+ case ISurfaceComposer::eRotateNone:
+ rotationFlags = Transform::ROT_0;
+ break;
+ case ISurfaceComposer::eRotate90:
+ rotationFlags = Transform::ROT_90;
+ break;
+ case ISurfaceComposer::eRotate180:
+ rotationFlags = Transform::ROT_180;
+ break;
+ case ISurfaceComposer::eRotate270:
+ rotationFlags = Transform::ROT_270;
+ break;
+ default:
+ rotationFlags = Transform::ROT_0;
+ ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
+ break;
+ }
+
+ class MessageCaptureScreen : public MessageBase {
+ SurfaceFlinger* flinger;
+ sp<IBinder> display;
+ sp<IGraphicBufferProducer> producer;
+ Rect sourceCrop;
+ uint32_t reqWidth, reqHeight;
+ uint32_t minLayerZ,maxLayerZ;
+ bool useIdentityTransform;
+ Transform::orientation_flags rotation;
+ status_t result;
+ bool isLocalScreenshot;
+ public:
+ MessageCaptureScreen(SurfaceFlinger* flinger,
+ const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool useIdentityTransform,
+ Transform::orientation_flags rotation,
+ bool isLocalScreenshot)
+ : flinger(flinger), display(display), producer(producer),
+ sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
+ minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
+ useIdentityTransform(useIdentityTransform),
+ rotation(rotation), result(PERMISSION_DENIED),
+ isLocalScreenshot(isLocalScreenshot)
+ {
+ }
+ status_t getResult() const {
+ return result;
+ }
+ virtual bool handler() {
+ Mutex::Autolock _l(flinger->mStateLock);
+ sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
+ result = flinger->captureScreenImplLocked(hw, producer,
+ sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ useIdentityTransform, rotation, isLocalScreenshot);
+ static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
+ return true;
+ }
+ };
+
+ // make sure to process transactions before screenshots -- a transaction
+ // might already be pending but scheduled for VSYNC; this guarantees we
+ // will handle it before the screenshot. When VSYNC finally arrives
+ // the scheduled transaction will be a no-op. If no transactions are
+ // scheduled at this time, this will end-up being a no-op as well.
+ mEventQueue.invalidateTransactionNow();
+
+ // this creates a "fake" BBinder which will serve as a "fake" remote
+ // binder to receive the marshaled calls and forward them to the
+ // real remote (a BpGraphicBufferProducer)
+ sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer);
+
+ // the asInterface() call below creates our "fake" BpGraphicBufferProducer
+ // which does the marshaling work forwards to our "fake remote" above.
+ sp<MessageBase> msg = new MessageCaptureScreen(this,
+ display, IGraphicBufferProducer::asInterface( wrapper ),
+ sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ useIdentityTransform, rotationFlags, isLocalScreenshot);
+
+ status_t res = postMessageAsync(msg);
+ if (res == NO_ERROR) {
+ res = wrapper->waitForResponse();
+ }
+ return res;
+}
+
+
+void SurfaceFlinger::renderScreenImplLocked(
+ const sp<const DisplayDevice>& hw,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation)
+{
+ ATRACE_CALL();
+ RenderEngine& engine(getRenderEngine());
+
+ // get screen geometry
+ const int32_t hw_w = hw->getWidth();
+ const int32_t hw_h = hw->getHeight();
+ const bool filtering = static_cast<int32_t>(reqWidth) != hw_w ||
+ static_cast<int32_t>(reqHeight) != hw_h;
+
+ // if a default or invalid sourceCrop is passed in, set reasonable values
+ if (sourceCrop.width() == 0 || sourceCrop.height() == 0 ||
+ !sourceCrop.isValid()) {
+ sourceCrop.setLeftTop(Point(0, 0));
+ sourceCrop.setRightBottom(Point(hw_w, hw_h));
+ }
+
+ // ensure that sourceCrop is inside screen
+ if (sourceCrop.left < 0) {
+ ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
+ }
+ if (sourceCrop.right > hw_w) {
+ ALOGE("Invalid crop rect: r = %d (> %d)", sourceCrop.right, hw_w);
+ }
+ if (sourceCrop.top < 0) {
+ ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
+ }
+ if (sourceCrop.bottom > hw_h) {
+ ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, hw_h);
+ }
+
+ // make sure to clear all GL error flags
+ engine.checkErrors();
+
+ // set-up our viewport
+ engine.setViewportAndProjection(
+ reqWidth, reqHeight, sourceCrop, hw_h, yswap, rotation);
+ engine.disableTexturing();
+
+ // redraw the screen entirely...
+ engine.clearWithColor(0, 0, 0, 1);
+
+ const LayerVector& layers( mDrawingState.layersSortedByZ );
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<Layer>& layer(layers[i]);
+ const Layer::State& state(layer->getDrawingState());
+ if (state.layerStack == hw->getLayerStack()) {
+ if (state.z >= minLayerZ && state.z <= maxLayerZ) {
+ if (layer->isVisible()) {
+ if (filtering) layer->setFiltering(true);
+ layer->draw(hw, useIdentityTransform);
+ if (filtering) layer->setFiltering(false);
+ }
+ }
+ }
+ }
+
+ // compositionComplete is needed for older driver
+ hw->compositionComplete();
+ hw->setViewportAndProjection();
+}
+
+
+status_t SurfaceFlinger::captureScreenImplLocked(
+ const sp<const DisplayDevice>& hw,
+ const sp<IGraphicBufferProducer>& producer,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool useIdentityTransform, Transform::orientation_flags rotation,
+ bool isLocalScreenshot)
+{
+ ATRACE_CALL();
+
+ // get screen geometry
+ uint32_t hw_w = hw->getWidth();
+ uint32_t hw_h = hw->getHeight();
+
+ if (rotation & Transform::ROT_90) {
+ std::swap(hw_w, hw_h);
+ }
+
+ if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
+ ALOGE("size mismatch (%d, %d) > (%d, %d)",
+ reqWidth, reqHeight, hw_w, hw_h);
+ return BAD_VALUE;
+ }
+
+ reqWidth = (!reqWidth) ? hw_w : reqWidth;
+ reqHeight = (!reqHeight) ? hw_h : reqHeight;
+
+ bool secureLayerIsVisible = false;
+ const LayerVector& layers(mDrawingState.layersSortedByZ);
+ const size_t count = layers.size();
+ for (size_t i = 0 ; i < count ; ++i) {
+ const sp<Layer>& layer(layers[i]);
+ const Layer::State& state(layer->getDrawingState());
+ if (state.layerStack == hw->getLayerStack() && state.z >= minLayerZ &&
+ state.z <= maxLayerZ && layer->isVisible() &&
+ layer->isSecure()) {
+ secureLayerIsVisible = true;
+ }
+ }
+
+ if (!isLocalScreenshot && secureLayerIsVisible) {
+ ALOGW("FB is protected: PERMISSION_DENIED");
+ return PERMISSION_DENIED;
+ }
+
+ // create a surface (because we're a producer, and we need to
+ // dequeue/queue a buffer)
+ sp<Surface> sur = new Surface(producer, false);
+ ANativeWindow* window = sur.get();
+
+ status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ if (result == NO_ERROR) {
+ uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+
+ int err = 0;
+ err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight);
+ err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
+ err |= native_window_set_usage(window, usage);
+
+ if (err == NO_ERROR) {
+ ANativeWindowBuffer* buffer;
+ /* TODO: Once we have the sync framework everywhere this can use
+ * server-side waits on the fence that dequeueBuffer returns.
+ */
+ result = native_window_dequeue_buffer_and_wait(window, &buffer);
+ if (result == NO_ERROR) {
+ int syncFd = -1;
+ // create an EGLImage from the buffer so we can later
+ // turn it into a texture
+ EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
+ if (image != EGL_NO_IMAGE_KHR) {
+ // this binds the given EGLImage as a framebuffer for the
+ // duration of this scope.
+ RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
+ if (imageBond.getStatus() == NO_ERROR) {
+ // this will in fact render into our dequeued buffer
+ // via an FBO, which means we didn't have to create
+ // an EGLSurface and therefore we're not
+ // dependent on the context's EGLConfig.
+ renderScreenImplLocked(
+ hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
+ useIdentityTransform, rotation);
+
+ // Attempt to create a sync khr object that can produce a sync point. If that
+ // isn't available, create a non-dupable sync object in the fallback path and
+ // wait on it directly.
+ EGLSyncKHR sync;
+ if (!DEBUG_SCREENSHOTS) {
+ sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+ // native fence fd will not be populated until flush() is done.
+ getRenderEngine().flush();
+ } else {
+ sync = EGL_NO_SYNC_KHR;
+ }
+ if (sync != EGL_NO_SYNC_KHR) {
+ // get the sync fd
+ syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
+ if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ALOGW("captureScreen: failed to dup sync khr object");
+ syncFd = -1;
+ }
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ } else {
+ // fallback path
+ sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
+ if (sync != EGL_NO_SYNC_KHR) {
+ EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
+ EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
+ EGLint eglErr = eglGetError();
+ if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ ALOGW("captureScreen: fence wait timed out");
+ } else {
+ ALOGW_IF(eglErr != EGL_SUCCESS,
+ "captureScreen: error waiting on EGL fence: %#x", eglErr);
+ }
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ } else {
+ ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
+ }
+ }
+ if (DEBUG_SCREENSHOTS) {
+ uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
+ getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
+ checkScreenshot(reqWidth, reqHeight, reqWidth, pixels,
+ hw, minLayerZ, maxLayerZ);
+ delete [] pixels;
+ }
+
+ } else {
+ ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
+ result = INVALID_OPERATION;
+ }
+ // destroy our image
+ eglDestroyImageKHR(mEGLDisplay, image);
+ } else {
+ result = BAD_VALUE;
+ }
+ // queueBuffer takes ownership of syncFd
+ result = window->queueBuffer(window, buffer, syncFd);
+ }
+ } else {
+ result = BAD_VALUE;
+ }
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ }
+
+ return result;
+}
+
+void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
+ const sp<const DisplayDevice>& hw, uint32_t minLayerZ, uint32_t maxLayerZ) {
+ if (DEBUG_SCREENSHOTS) {
+ for (size_t y=0 ; y<h ; y++) {
+ uint32_t const * p = (uint32_t const *)vaddr + y*s;
+ for (size_t x=0 ; x<w ; x++) {
+ if (p[x] != 0xFF000000) return;
+ }
+ }
+ ALOGE("*** we just took a black screenshot ***\n"
+ "requested minz=%d, maxz=%d, layerStack=%d",
+ minLayerZ, maxLayerZ, hw->getLayerStack());
+ const LayerVector& layers( mDrawingState.layersSortedByZ );
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<Layer>& layer(layers[i]);
+ const Layer::State& state(layer->getDrawingState());
+ const bool visible = (state.layerStack == hw->getLayerStack())
+ && (state.z >= minLayerZ && state.z <= maxLayerZ)
+ && (layer->isVisible());
+ ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%x",
+ visible ? '+' : '-',
+ i, layer->getName().string(), state.layerStack, state.z,
+ layer->isVisible(), state.flags, state.alpha);
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+SurfaceFlinger::LayerVector::LayerVector() {
+}
+
+SurfaceFlinger::LayerVector::LayerVector(const LayerVector& rhs)
+ : SortedVector<sp<Layer> >(rhs) {
+}
+
+int SurfaceFlinger::LayerVector::do_compare(const void* lhs,
+ const void* rhs) const
+{
+ // sort layers per layer-stack, then by z-order and finally by sequence
+ const sp<Layer>& l(*reinterpret_cast<const sp<Layer>*>(lhs));
+ const sp<Layer>& r(*reinterpret_cast<const sp<Layer>*>(rhs));
+
+ uint32_t ls = l->getCurrentState().layerStack;
+ uint32_t rs = r->getCurrentState().layerStack;
+ if (ls != rs)
+ return ls - rs;
+
+ uint32_t lz = l->getCurrentState().z;
+ uint32_t rz = r->getCurrentState().z;
+ if (lz != rz)
+ return lz - rz;
+
+ return l->sequence - r->sequence;
+}
+
+// ---------------------------------------------------------------------------
+
+SurfaceFlinger::DisplayDeviceState::DisplayDeviceState()
+ : type(DisplayDevice::DISPLAY_ID_INVALID),
+ layerStack(DisplayDevice::NO_LAYER_STACK),
+ orientation(0),
+ width(0),
+ height(0),
+ isSecure(false) {
+}
+
+SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(
+ DisplayDevice::DisplayType type, bool isSecure)
+ : type(type),
+ layerStack(DisplayDevice::NO_LAYER_STACK),
+ orientation(0),
+ width(0),
+ height(0),
+ isSecure(isSecure) {
+ viewport.makeInvalid();
+ frame.makeInvalid();
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+
+#if defined(__gl_h_)
+#error "don't include gl/gl.h in this file"
+#endif
+
+#if defined(__gl2_h_)
+#error "don't include gl2/gl2.h in this file"
+#endif