Revert "Delete HWC1"
This reverts commit 90f923493fa053655a203c34ea491086aeb07602.
Change-Id: If9da49e3bc85f8ff21ac1bd22a6bab97e9aa3103
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
index d39a3aa..d801bb3 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
@@ -49,6 +49,14 @@
};
virtual status_t prepareFrame(CompositionType compositionType) = 0;
+#ifndef USE_HWC2
+ // Should be called when composition rendering is complete for a frame (but
+ // eglSwapBuffers hasn't necessarily been called). Required by certain
+ // older drivers for synchronization.
+ // TODO: Remove this when we drop support for HWC 1.0.
+ virtual status_t compositionComplete() = 0;
+#endif
+
// Inform the surface that GLES composition is complete for this frame, and
// the surface should make sure that HWComposer has the correct buffer for
// this frame. Some implementations may only push a new buffer to
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index a50b550..18c7945 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -62,20 +62,32 @@
mCurrentBufferSlot(-1),
mCurrentBuffer(),
mCurrentFence(Fence::NO_FENCE),
+#ifdef USE_HWC2
mHwc(hwc),
mHasPendingRelease(false),
mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
mPreviousBuffer()
+#else
+ mHwc(hwc)
+#endif
{
+#ifdef USE_HWC2
ALOGV("Creating for display %d", disp);
+#endif
+
mName = "FramebufferSurface";
mConsumer->setConsumerName(mName);
mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_COMPOSER);
+#ifdef USE_HWC2
const auto& activeConfig = mHwc.getActiveConfig(disp);
mConsumer->setDefaultBufferSize(activeConfig->getWidth(),
activeConfig->getHeight());
+#else
+ mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp));
+ mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp));
+#endif
mConsumer->setMaxAcquiredBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS - 1);
}
@@ -88,6 +100,7 @@
}
status_t FramebufferSurface::advanceFrame() {
+#ifdef USE_HWC2
sp<GraphicBuffer> buf;
sp<Fence> acquireFence(Fence::NO_FENCE);
android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
@@ -102,10 +115,20 @@
ALOGE("error posting framebuffer: %d", result);
}
return result;
+#else
+ // Once we remove FB HAL support, we can call nextBuffer() from here
+ // instead of using onFrameAvailable(). No real benefit, except it'll be
+ // more like VirtualDisplaySurface.
+ return NO_ERROR;
+#endif
}
+#ifdef USE_HWC2
status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer,
sp<Fence>& outFence, android_dataspace_t& outDataspace) {
+#else
+status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence) {
+#endif
Mutex::Autolock lock(mMutex);
BufferItem item;
@@ -128,9 +151,19 @@
// had released the old buffer first.
if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT &&
item.mSlot != mCurrentBufferSlot) {
+#ifdef USE_HWC2
mHasPendingRelease = true;
mPreviousBufferSlot = mCurrentBufferSlot;
mPreviousBuffer = mCurrentBuffer;
+#else
+ // Release the previous buffer.
+ err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+ if (err < NO_ERROR) {
+ ALOGE("error releasing buffer: %s (%d)", strerror(-err), err);
+ return err;
+ }
+#endif
}
mCurrentBufferSlot = item.mSlot;
mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
@@ -138,10 +171,30 @@
outFence = item.mFence;
outBuffer = mCurrentBuffer;
+#ifdef USE_HWC2
outDataspace = item.mDataSpace;
+#endif
return NO_ERROR;
}
+#ifndef USE_HWC2
+// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl.
+void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) {
+ sp<GraphicBuffer> buf;
+ sp<Fence> acquireFence;
+ status_t err = nextBuffer(buf, acquireFence);
+ if (err != NO_ERROR) {
+ ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)",
+ strerror(-err), err);
+ return;
+ }
+ err = mHwc.fbPost(mDisplayType, acquireFence, buf);
+ if (err != NO_ERROR) {
+ ALOGE("error posting framebuffer: %d", err);
+ }
+}
+#endif
+
void FramebufferSurface::freeBufferLocked(int slotIndex) {
ConsumerBase::freeBufferLocked(slotIndex);
if (slotIndex == mCurrentBufferSlot) {
@@ -150,6 +203,7 @@
}
void FramebufferSurface::onFrameCommitted() {
+#ifdef USE_HWC2
if (mHasPendingRelease) {
sp<Fence> fence = mHwc.getRetireFence(mDisplayType);
if (fence->isValid()) {
@@ -166,14 +220,34 @@
mPreviousBuffer.clear();
mHasPendingRelease = false;
}
+#else
+ sp<Fence> fence = mHwc.getAndResetReleaseFence(mDisplayType);
+ if (fence->isValid() &&
+ mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) {
+ status_t err = addReleaseFence(mCurrentBufferSlot,
+ mCurrentBuffer, fence);
+ ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)",
+ strerror(-err), err);
+ }
+#endif
}
+#ifndef USE_HWC2
+status_t FramebufferSurface::compositionComplete()
+{
+ return mHwc.fbCompositionComplete();
+}
+#endif
+
void FramebufferSurface::dumpAsString(String8& result) const {
ConsumerBase::dumpState(result);
}
void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const
{
+#ifndef USE_HWC2
+ mHwc.fbDump(result);
+#endif
ConsumerBase::dumpLocked(result, prefix);
}
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index eb70479..439435a 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -41,6 +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;
@@ -54,6 +57,9 @@
private:
virtual ~FramebufferSurface() { }; // this class cannot be overloaded
+#ifndef USE_HWC2
+ virtual void onFrameAvailable(const BufferItem& item);
+#endif
virtual void freeBufferLocked(int slotIndex);
virtual void dumpLocked(String8& result, const char* prefix) const;
@@ -61,8 +67,12 @@
// nextBuffer waits for and then latches the next buffer from the
// BufferQueue and releases the previously latched buffer to the
// BufferQueue. The new buffer is returned in the 'buffer' argument.
+#ifdef USE_HWC2
status_t nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence,
android_dataspace_t& outDataspace);
+#else
+ status_t nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence);
+#endif
// mDisplayType must match one of the HWC display types
int mDisplayType;
@@ -82,10 +92,12 @@
// Hardware composer, owned by SurfaceFlinger.
HWComposer& mHwc;
+#ifdef USE_HWC2
// Previous buffer to release after getting an updated retire fence
bool mHasPendingRelease;
int mPreviousBufferSlot;
sp<GraphicBuffer> mPreviousBuffer;
+#endif
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index b25f5ad..41671f6 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#ifndef USE_HWC2
+#include "HWComposer_hwc1.h"
+#else
+
#ifndef ANDROID_SF_HWCOMPOSER_H
#define ANDROID_SF_HWCOMPOSER_H
@@ -220,3 +224,5 @@
}; // 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..2102457
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
@@ -0,0 +1,1344 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <inttypes.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/misc.h>
+#include <utils/NativeHandle.h>
+#include <utils/String8.h>
+#include <utils/Thread.h>
+#include <utils/Trace.h>
+#include <utils/Vector.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+
+#include <android/configuration.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include <system/graphics.h>
+
+#include "HWComposer.h"
+
+#include "../Layer.h" // needed only for debugging
+#include "../SurfaceFlinger.h"
+
+namespace android {
+
+#define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION
+
+static uint32_t hwcApiVersion(const hwc_composer_device_1_t* hwc) {
+ uint32_t hwcVersion = hwc->common.version;
+ return hwcVersion & HARDWARE_API_VERSION_2_MAJ_MIN_MASK;
+}
+
+static uint32_t hwcHeaderVersion(const hwc_composer_device_1_t* hwc) {
+ uint32_t hwcVersion = hwc->common.version;
+ return hwcVersion & HARDWARE_API_VERSION_2_HEADER_MASK;
+}
+
+static bool hwcHasApiVersion(const hwc_composer_device_1_t* hwc,
+ uint32_t version) {
+ return hwcApiVersion(hwc) >= (version & HARDWARE_API_VERSION_2_MAJ_MIN_MASK);
+}
+
+// ---------------------------------------------------------------------------
+
+struct HWComposer::cb_context {
+ struct callbacks : public hwc_procs_t {
+ // these are here to facilitate the transition when adding
+ // new callbacks (an implementation can check for NULL before
+ // calling a new callback).
+ void (*zero[4])(void);
+ };
+ callbacks procs;
+ HWComposer* hwc;
+};
+
+// ---------------------------------------------------------------------------
+
+HWComposer::HWComposer(
+ const sp<SurfaceFlinger>& flinger,
+ EventHandler& handler)
+ : mFlinger(flinger),
+ mFbDev(0), mHwc(0), mNumDisplays(1),
+ mCBContext(new cb_context),
+ mEventHandler(handler),
+ mDebugForceFakeVSync(false)
+{
+ for (size_t i =0 ; i<MAX_HWC_DISPLAYS ; i++) {
+ mLists[i] = 0;
+ }
+
+ for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) {
+ mLastHwVSync[i] = 0;
+ mVSyncCounts[i] = 0;
+ }
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.no_hw_vsync", value, "0");
+ mDebugForceFakeVSync = atoi(value);
+
+ bool needVSyncThread = true;
+
+ // Note: some devices may insist that the FB HAL be opened before HWC.
+ int fberr = loadFbHalModule();
+ loadHwcModule();
+
+ if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // close FB HAL if we don't needed it.
+ // FIXME: this is temporary until we're not forced to open FB HAL
+ // before HWC.
+ framebuffer_close(mFbDev);
+ mFbDev = NULL;
+ }
+
+ // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory.
+ if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
+ && !mFbDev) {
+ ALOGE("ERROR: failed to open framebuffer (%s), aborting",
+ strerror(-fberr));
+ abort();
+ }
+
+ // these display IDs are always reserved
+ for (size_t i=0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {
+ mAllocatedDisplayIDs.markBit(i);
+ }
+
+ if (mHwc) {
+ ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
+ (hwcApiVersion(mHwc) >> 24) & 0xff,
+ (hwcApiVersion(mHwc) >> 16) & 0xff);
+ if (mHwc->registerProcs) {
+ mCBContext->hwc = this;
+ mCBContext->procs.invalidate = &hook_invalidate;
+ mCBContext->procs.vsync = &hook_vsync;
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
+ mCBContext->procs.hotplug = &hook_hotplug;
+ else
+ mCBContext->procs.hotplug = NULL;
+ memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
+ mHwc->registerProcs(mHwc, &mCBContext->procs);
+ }
+
+ // don't need a vsync thread if we have a hardware composer
+ needVSyncThread = false;
+ // always turn vsync off when we start
+ eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
+
+ // the number of displays we actually have depends on the
+ // hw composer version
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+ // 1.3 adds support for virtual displays
+ mNumDisplays = MAX_HWC_DISPLAYS;
+ } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // 1.1 adds support for multiple displays
+ mNumDisplays = NUM_BUILTIN_DISPLAYS;
+ } else {
+ mNumDisplays = 1;
+ }
+ }
+
+ if (mFbDev) {
+ ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)),
+ "should only have fbdev if no hwc or hwc is 1.0");
+
+ DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
+ disp.connected = true;
+ disp.format = mFbDev->format;
+ DisplayConfig config = DisplayConfig();
+ config.width = mFbDev->width;
+ config.height = mFbDev->height;
+ config.xdpi = mFbDev->xdpi;
+ config.ydpi = mFbDev->ydpi;
+ config.refresh = nsecs_t(1e9 / mFbDev->fps);
+ disp.configs.push_back(config);
+ disp.currentConfig = 0;
+ } else if (mHwc) {
+ // here we're guaranteed to have at least HWC 1.1
+ for (size_t i =0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {
+ queryDisplayProperties(i);
+ }
+ }
+
+ if (needVSyncThread) {
+ // we don't have VSYNC support, we need to fake it
+ mVSyncThread = new VSyncThread(*this);
+ }
+}
+
+HWComposer::~HWComposer() {
+ if (mHwc) {
+ eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
+ }
+ if (mVSyncThread != NULL) {
+ mVSyncThread->requestExitAndWait();
+ }
+ if (mHwc) {
+ hwc_close_1(mHwc);
+ }
+ if (mFbDev) {
+ framebuffer_close(mFbDev);
+ }
+ delete mCBContext;
+}
+
+// Load and prepare the hardware composer module. Sets mHwc.
+void HWComposer::loadHwcModule()
+{
+ hw_module_t const* module;
+
+ if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
+ ALOGE("%s module not found", HWC_HARDWARE_MODULE_ID);
+ return;
+ }
+
+ int err = hwc_open_1(module, &mHwc);
+ if (err) {
+ ALOGE("%s device failed to initialize (%s)",
+ HWC_HARDWARE_COMPOSER, strerror(-err));
+ return;
+ }
+
+ if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) ||
+ hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION ||
+ hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) {
+ ALOGE("%s device version %#x unsupported, will not be used",
+ HWC_HARDWARE_COMPOSER, mHwc->common.version);
+ hwc_close_1(mHwc);
+ mHwc = NULL;
+ return;
+ }
+}
+
+// Load and prepare the FB HAL, which uses the gralloc module. Sets mFbDev.
+int HWComposer::loadFbHalModule()
+{
+ hw_module_t const* module;
+
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ if (err != 0) {
+ ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID);
+ return err;
+ }
+
+ return framebuffer_open(module, &mFbDev);
+}
+
+status_t HWComposer::initCheck() const {
+ return mHwc ? NO_ERROR : NO_INIT;
+}
+
+void HWComposer::hook_invalidate(const struct hwc_procs* procs) {
+ cb_context* ctx = reinterpret_cast<cb_context*>(
+ const_cast<hwc_procs_t*>(procs));
+ ctx->hwc->invalidate();
+}
+
+void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp,
+ int64_t timestamp) {
+ cb_context* ctx = reinterpret_cast<cb_context*>(
+ const_cast<hwc_procs_t*>(procs));
+ ctx->hwc->vsync(disp, timestamp);
+}
+
+void HWComposer::hook_hotplug(const struct hwc_procs* procs, int disp,
+ int connected) {
+ cb_context* ctx = reinterpret_cast<cb_context*>(
+ const_cast<hwc_procs_t*>(procs));
+ ctx->hwc->hotplug(disp, connected);
+}
+
+void HWComposer::invalidate() {
+ mFlinger->repaintEverything();
+}
+
+void HWComposer::vsync(int disp, int64_t timestamp) {
+ if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+ {
+ Mutex::Autolock _l(mLock);
+
+ // There have been reports of HWCs that signal several vsync events
+ // with the same timestamp when turning the display off and on. This
+ // is a bug in the HWC implementation, but filter the extra events
+ // out here so they don't cause havoc downstream.
+ if (timestamp == mLastHwVSync[disp]) {
+ ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
+ timestamp);
+ return;
+ }
+
+ mLastHwVSync[disp] = timestamp;
+ }
+
+ char tag[16];
+ snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
+ ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
+
+ mEventHandler.onVSyncReceived(disp, timestamp);
+ }
+}
+
+void HWComposer::hotplug(int disp, int connected) {
+ if (disp >= VIRTUAL_DISPLAY_ID_BASE) {
+ ALOGE("hotplug event received for invalid display: disp=%d connected=%d",
+ disp, connected);
+ return;
+ }
+ queryDisplayProperties(disp);
+ // Do not teardown or recreate the primary display
+ if (disp != HWC_DISPLAY_PRIMARY) {
+ mEventHandler.onHotplugReceived(disp, bool(connected));
+ }
+}
+
+static float getDefaultDensity(uint32_t width, uint32_t height) {
+ // Default density is based on TVs: 1080p displays get XHIGH density,
+ // lower-resolution displays get TV density. Maybe eventually we'll need
+ // to update it for 4K displays, though hopefully those just report
+ // accurate DPI information to begin with. This is also used for virtual
+ // displays and even primary displays with older hwcomposers, so be
+ // careful about orientation.
+
+ uint32_t h = width < height ? width : height;
+ if (h >= 1080) return ACONFIGURATION_DENSITY_XHIGH;
+ else return ACONFIGURATION_DENSITY_TV;
+}
+
+static const uint32_t DISPLAY_ATTRIBUTES[] = {
+ HWC_DISPLAY_VSYNC_PERIOD,
+ HWC_DISPLAY_WIDTH,
+ HWC_DISPLAY_HEIGHT,
+ HWC_DISPLAY_DPI_X,
+ HWC_DISPLAY_DPI_Y,
+ HWC_DISPLAY_COLOR_TRANSFORM,
+ HWC_DISPLAY_NO_ATTRIBUTE,
+};
+#define NUM_DISPLAY_ATTRIBUTES (sizeof(DISPLAY_ATTRIBUTES) / sizeof(DISPLAY_ATTRIBUTES)[0])
+
+static const uint32_t PRE_HWC15_DISPLAY_ATTRIBUTES[] = {
+ HWC_DISPLAY_VSYNC_PERIOD,
+ HWC_DISPLAY_WIDTH,
+ HWC_DISPLAY_HEIGHT,
+ HWC_DISPLAY_DPI_X,
+ HWC_DISPLAY_DPI_Y,
+ HWC_DISPLAY_NO_ATTRIBUTE,
+};
+
+status_t HWComposer::queryDisplayProperties(int disp) {
+
+ LOG_ALWAYS_FATAL_IF(!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
+
+ // use zero as default value for unspecified attributes
+ int32_t values[NUM_DISPLAY_ATTRIBUTES - 1];
+ memset(values, 0, sizeof(values));
+
+ const size_t MAX_NUM_CONFIGS = 128;
+ uint32_t configs[MAX_NUM_CONFIGS] = {0};
+ size_t numConfigs = MAX_NUM_CONFIGS;
+ status_t err = mHwc->getDisplayConfigs(mHwc, disp, configs, &numConfigs);
+ if (err != NO_ERROR) {
+ // this can happen if an unpluggable display is not connected
+ mDisplayData[disp].connected = false;
+ return err;
+ }
+
+ mDisplayData[disp].currentConfig = 0;
+ for (size_t c = 0; c < numConfigs; ++c) {
+ err = mHwc->getDisplayAttributes(mHwc, disp, configs[c],
+ DISPLAY_ATTRIBUTES, values);
+ // If this is a pre-1.5 HWC, it may not know about color transform, so
+ // try again with a smaller set of attributes
+ if (err != NO_ERROR) {
+ err = mHwc->getDisplayAttributes(mHwc, disp, configs[c],
+ PRE_HWC15_DISPLAY_ATTRIBUTES, values);
+ }
+ if (err != NO_ERROR) {
+ // we can't get this display's info. turn it off.
+ mDisplayData[disp].connected = false;
+ return err;
+ }
+
+ DisplayConfig config = DisplayConfig();
+ for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) {
+ switch (DISPLAY_ATTRIBUTES[i]) {
+ case HWC_DISPLAY_VSYNC_PERIOD:
+ config.refresh = nsecs_t(values[i]);
+ break;
+ case HWC_DISPLAY_WIDTH:
+ config.width = values[i];
+ break;
+ case HWC_DISPLAY_HEIGHT:
+ config.height = values[i];
+ break;
+ case HWC_DISPLAY_DPI_X:
+ config.xdpi = values[i] / 1000.0f;
+ break;
+ case HWC_DISPLAY_DPI_Y:
+ config.ydpi = values[i] / 1000.0f;
+ break;
+ case HWC_DISPLAY_COLOR_TRANSFORM:
+ config.colorMode = static_cast<android_color_mode_t>(values[i]);
+ break;
+ default:
+ ALOG_ASSERT(false, "unknown display attribute[%zu] %#x",
+ i, DISPLAY_ATTRIBUTES[i]);
+ break;
+ }
+ }
+
+ if (config.xdpi == 0.0f || config.ydpi == 0.0f) {
+ float dpi = getDefaultDensity(config.width, config.height);
+ config.xdpi = dpi;
+ config.ydpi = dpi;
+ }
+
+ mDisplayData[disp].configs.push_back(config);
+ }
+
+ // FIXME: what should we set the format to?
+ mDisplayData[disp].format = HAL_PIXEL_FORMAT_RGBA_8888;
+ mDisplayData[disp].connected = true;
+ return NO_ERROR;
+}
+
+status_t HWComposer::setVirtualDisplayProperties(int32_t id,
+ uint32_t w, uint32_t h, uint32_t format) {
+ if (id < VIRTUAL_DISPLAY_ID_BASE || id >= int32_t(mNumDisplays) ||
+ !mAllocatedDisplayIDs.hasBit(id)) {
+ return BAD_INDEX;
+ }
+ size_t configId = mDisplayData[id].currentConfig;
+ mDisplayData[id].format = format;
+ DisplayConfig& config = mDisplayData[id].configs.editItemAt(configId);
+ config.width = w;
+ config.height = h;
+ config.xdpi = config.ydpi = getDefaultDensity(w, h);
+ return NO_ERROR;
+}
+
+int32_t HWComposer::allocateDisplayId() {
+ if (mAllocatedDisplayIDs.count() >= mNumDisplays) {
+ return NO_MEMORY;
+ }
+ int32_t id = mAllocatedDisplayIDs.firstUnmarkedBit();
+ mAllocatedDisplayIDs.markBit(id);
+ mDisplayData[id].connected = true;
+ mDisplayData[id].configs.resize(1);
+ mDisplayData[id].currentConfig = 0;
+ return id;
+}
+
+status_t HWComposer::freeDisplayId(int32_t id) {
+ if (id < NUM_BUILTIN_DISPLAYS) {
+ // cannot free the reserved IDs
+ return BAD_VALUE;
+ }
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+ return BAD_INDEX;
+ }
+ mAllocatedDisplayIDs.clearBit(id);
+ mDisplayData[id].connected = false;
+ return NO_ERROR;
+}
+
+nsecs_t HWComposer::getRefreshTimestamp(int disp) const {
+ // this returns the last refresh timestamp.
+ // if the last one is not available, we estimate it based on
+ // the refresh period and whatever closest timestamp we have.
+ Mutex::Autolock _l(mLock);
+ nsecs_t now = systemTime(CLOCK_MONOTONIC);
+ size_t configId = mDisplayData[disp].currentConfig;
+ return now - ((now - mLastHwVSync[disp]) %
+ mDisplayData[disp].configs[configId].refresh);
+}
+
+sp<Fence> HWComposer::getDisplayFence(int disp) const {
+ return mDisplayData[disp].lastDisplayFence;
+}
+
+uint32_t HWComposer::getFormat(int disp) const {
+ if (static_cast<uint32_t>(disp) >= MAX_HWC_DISPLAYS || !mAllocatedDisplayIDs.hasBit(disp)) {
+ return HAL_PIXEL_FORMAT_RGBA_8888;
+ } else {
+ return mDisplayData[disp].format;
+ }
+}
+
+bool HWComposer::isConnected(int disp) const {
+ return mDisplayData[disp].connected;
+}
+
+uint32_t HWComposer::getWidth(int disp) const {
+ size_t currentConfig = mDisplayData[disp].currentConfig;
+ return mDisplayData[disp].configs[currentConfig].width;
+}
+
+uint32_t HWComposer::getHeight(int disp) const {
+ size_t currentConfig = mDisplayData[disp].currentConfig;
+ return mDisplayData[disp].configs[currentConfig].height;
+}
+
+float HWComposer::getDpiX(int disp) const {
+ size_t currentConfig = mDisplayData[disp].currentConfig;
+ return mDisplayData[disp].configs[currentConfig].xdpi;
+}
+
+float HWComposer::getDpiY(int disp) const {
+ size_t currentConfig = mDisplayData[disp].currentConfig;
+ return mDisplayData[disp].configs[currentConfig].ydpi;
+}
+
+nsecs_t HWComposer::getRefreshPeriod(int disp) const {
+ size_t currentConfig = mDisplayData[disp].currentConfig;
+ return mDisplayData[disp].configs[currentConfig].refresh;
+}
+
+android_color_mode_t HWComposer::getColorMode(int disp) const {
+ size_t currentConfig = mDisplayData[disp].currentConfig;
+ return mDisplayData[disp].configs[currentConfig].colorMode;
+}
+
+const Vector<HWComposer::DisplayConfig>& HWComposer::getConfigs(int disp) const {
+ return mDisplayData[disp].configs;
+}
+
+size_t HWComposer::getCurrentConfig(int disp) const {
+ return mDisplayData[disp].currentConfig;
+}
+
+void HWComposer::eventControl(int disp, int event, int enabled) {
+ if (uint32_t(disp)>31 || !mAllocatedDisplayIDs.hasBit(disp)) {
+ ALOGD("eventControl ignoring event %d on unallocated disp %d (en=%d)",
+ event, disp, enabled);
+ return;
+ }
+ if (event != EVENT_VSYNC) {
+ ALOGW("eventControl got unexpected event %d (disp=%d en=%d)",
+ event, disp, enabled);
+ return;
+ }
+ status_t err = NO_ERROR;
+ if (mHwc && !mDebugForceFakeVSync) {
+ // NOTE: we use our own internal lock here because we have to call
+ // into the HWC with the lock held, and we want to make sure
+ // that even if HWC blocks (which it shouldn't), it won't
+ // affect other threads.
+ Mutex::Autolock _l(mEventControlLock);
+ const int32_t eventBit = 1UL << event;
+ const int32_t newValue = enabled ? eventBit : 0;
+ const int32_t oldValue = mDisplayData[disp].events & eventBit;
+ if (newValue != oldValue) {
+ ATRACE_CALL();
+ err = mHwc->eventControl(mHwc, disp, event, enabled);
+ if (!err) {
+ int32_t& events(mDisplayData[disp].events);
+ events = (events & ~eventBit) | newValue;
+
+ char tag[16];
+ snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", disp);
+ ATRACE_INT(tag, enabled);
+ }
+ }
+ // error here should not happen -- not sure what we should
+ // do if it does.
+ ALOGE_IF(err, "eventControl(%d, %d) failed %s",
+ event, enabled, strerror(-err));
+ }
+
+ if (err == NO_ERROR && mVSyncThread != NULL) {
+ mVSyncThread->setEnabled(enabled);
+ }
+}
+
+status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+ return BAD_INDEX;
+ }
+
+ if (mHwc) {
+ DisplayData& disp(mDisplayData[id]);
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // we need space for the HWC_FRAMEBUFFER_TARGET
+ numLayers++;
+ }
+ if (disp.capacity < numLayers || disp.list == NULL) {
+ size_t size = sizeof(hwc_display_contents_1_t)
+ + numLayers * sizeof(hwc_layer_1_t);
+ free(disp.list);
+ disp.list = (hwc_display_contents_1_t*)malloc(size);
+ disp.capacity = numLayers;
+ }
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ disp.framebufferTarget = &disp.list->hwLayers[numLayers - 1];
+ memset(disp.framebufferTarget, 0, sizeof(hwc_layer_1_t));
+ const DisplayConfig& currentConfig =
+ disp.configs[disp.currentConfig];
+ const hwc_rect_t r = { 0, 0,
+ (int) currentConfig.width, (int) currentConfig.height };
+ disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
+ disp.framebufferTarget->hints = 0;
+ disp.framebufferTarget->flags = 0;
+ disp.framebufferTarget->handle = disp.fbTargetHandle;
+ disp.framebufferTarget->transform = 0;
+ disp.framebufferTarget->blending = HWC_BLENDING_PREMULT;
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+ disp.framebufferTarget->sourceCropf.left = 0;
+ disp.framebufferTarget->sourceCropf.top = 0;
+ disp.framebufferTarget->sourceCropf.right =
+ currentConfig.width;
+ disp.framebufferTarget->sourceCropf.bottom =
+ currentConfig.height;
+ } else {
+ disp.framebufferTarget->sourceCrop = r;
+ }
+ disp.framebufferTarget->displayFrame = r;
+ disp.framebufferTarget->visibleRegionScreen.numRects = 1;
+ disp.framebufferTarget->visibleRegionScreen.rects =
+ &disp.framebufferTarget->displayFrame;
+ disp.framebufferTarget->acquireFenceFd = -1;
+ disp.framebufferTarget->releaseFenceFd = -1;
+ disp.framebufferTarget->planeAlpha = 0xFF;
+ }
+ disp.list->retireFenceFd = -1;
+ disp.list->flags = HWC_GEOMETRY_CHANGED;
+ disp.list->numHwLayers = numLayers;
+ }
+ return NO_ERROR;
+}
+
+status_t HWComposer::setFramebufferTarget(int32_t id,
+ const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf) {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+ return BAD_INDEX;
+ }
+ DisplayData& disp(mDisplayData[id]);
+ if (!disp.framebufferTarget) {
+ // this should never happen, but apparently eglCreateWindowSurface()
+ // triggers a Surface::queueBuffer() on some
+ // devices (!?) -- log and ignore.
+ ALOGE("HWComposer: framebufferTarget is null");
+ return NO_ERROR;
+ }
+
+ int acquireFenceFd = -1;
+ if (acquireFence->isValid()) {
+ acquireFenceFd = acquireFence->dup();
+ }
+
+ // ALOGD("fbPost: handle=%p, fence=%d", buf->handle, acquireFenceFd);
+ disp.fbTargetHandle = buf->handle;
+ disp.framebufferTarget->handle = disp.fbTargetHandle;
+ disp.framebufferTarget->acquireFenceFd = acquireFenceFd;
+ return NO_ERROR;
+}
+
+status_t HWComposer::prepare() {
+ Mutex::Autolock _l(mDisplayLock);
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ DisplayData& disp(mDisplayData[i]);
+ if (disp.framebufferTarget) {
+ // make sure to reset the type to HWC_FRAMEBUFFER_TARGET
+ // DO NOT reset the handle field to NULL, because it's possible
+ // that we have nothing to redraw (eg: eglSwapBuffers() not called)
+ // in which case, we should continue to use the same buffer.
+ LOG_FATAL_IF(disp.list == NULL);
+ disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
+ }
+ if (!disp.connected && disp.list != NULL) {
+ ALOGW("WARNING: disp %zu: connected, non-null list, layers=%zu",
+ i, disp.list->numHwLayers);
+ }
+ mLists[i] = disp.list;
+ if (mLists[i]) {
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+ mLists[i]->outbuf = disp.outbufHandle;
+ mLists[i]->outbufAcquireFenceFd = -1;
+ } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // garbage data to catch improper use
+ mLists[i]->dpy = (hwc_display_t)0xDEADBEEF;
+ mLists[i]->sur = (hwc_surface_t)0xDEADBEEF;
+ } else {
+ mLists[i]->dpy = EGL_NO_DISPLAY;
+ mLists[i]->sur = EGL_NO_SURFACE;
+ }
+ }
+ }
+
+ int err = mHwc->prepare(mHwc, mNumDisplays, mLists);
+ ALOGE_IF(err, "HWComposer: prepare failed (%s)", strerror(-err));
+
+ if (err == NO_ERROR) {
+ // here we're just making sure that "skip" layers are set
+ // to HWC_FRAMEBUFFER and we're also counting how many layers
+ // we have of each type.
+ //
+ // If there are no window layers, we treat the display has having FB
+ // composition, because SurfaceFlinger will use GLES to draw the
+ // wormhole region.
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ DisplayData& disp(mDisplayData[i]);
+ disp.hasFbComp = false;
+ disp.hasOvComp = false;
+ if (disp.list) {
+ for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
+ hwc_layer_1_t& l = disp.list->hwLayers[i];
+
+ //ALOGD("prepare: %d, type=%d, handle=%p",
+ // i, l.compositionType, l.handle);
+
+ if (l.flags & HWC_SKIP_LAYER) {
+ l.compositionType = HWC_FRAMEBUFFER;
+ }
+ if (l.compositionType == HWC_FRAMEBUFFER) {
+ disp.hasFbComp = true;
+ }
+ if (l.compositionType == HWC_OVERLAY) {
+ disp.hasOvComp = true;
+ }
+ if (l.compositionType == HWC_CURSOR_OVERLAY) {
+ disp.hasOvComp = true;
+ }
+ }
+ if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) {
+ disp.hasFbComp = true;
+ }
+ } else {
+ disp.hasFbComp = true;
+ }
+ }
+ }
+ return (status_t)err;
+}
+
+bool HWComposer::hasHwcComposition(int32_t id) const {
+ if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ return false;
+ return mDisplayData[id].hasOvComp;
+}
+
+bool HWComposer::hasGlesComposition(int32_t id) const {
+ if (!mHwc || uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ return true;
+ return mDisplayData[id].hasFbComp;
+}
+
+sp<Fence> HWComposer::getAndResetReleaseFence(int32_t id) {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ return Fence::NO_FENCE;
+
+ int fd = INVALID_OPERATION;
+ if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ const DisplayData& disp(mDisplayData[id]);
+ if (disp.framebufferTarget) {
+ fd = disp.framebufferTarget->releaseFenceFd;
+ disp.framebufferTarget->acquireFenceFd = -1;
+ disp.framebufferTarget->releaseFenceFd = -1;
+ }
+ }
+ return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE;
+}
+
+status_t HWComposer::commit() {
+ int err = NO_ERROR;
+ if (mHwc) {
+ if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // On version 1.0, the OpenGL ES target surface is communicated
+ // by the (dpy, sur) fields and we are guaranteed to have only
+ // a single display.
+ mLists[0]->dpy = eglGetCurrentDisplay();
+ mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW);
+ }
+
+ for (size_t i=VIRTUAL_DISPLAY_ID_BASE; i<mNumDisplays; i++) {
+ DisplayData& disp(mDisplayData[i]);
+ if (disp.outbufHandle) {
+ mLists[i]->outbuf = disp.outbufHandle;
+ mLists[i]->outbufAcquireFenceFd =
+ disp.outbufAcquireFence->dup();
+ }
+ }
+
+ err = mHwc->set(mHwc, mNumDisplays, mLists);
+
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ DisplayData& disp(mDisplayData[i]);
+ disp.lastDisplayFence = disp.lastRetireFence;
+ disp.lastRetireFence = Fence::NO_FENCE;
+ if (disp.list) {
+ if (disp.list->retireFenceFd != -1) {
+ disp.lastRetireFence = new Fence(disp.list->retireFenceFd);
+ disp.list->retireFenceFd = -1;
+ }
+ disp.list->flags &= ~HWC_GEOMETRY_CHANGED;
+ }
+ }
+ }
+ return (status_t)err;
+}
+
+status_t HWComposer::setPowerMode(int disp, int mode) {
+ LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE);
+ if (mHwc) {
+ if (mode == HWC_POWER_MODE_OFF) {
+ eventControl(disp, HWC_EVENT_VSYNC, 0);
+ }
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
+ return (status_t)mHwc->setPowerMode(mHwc, disp, mode);
+ } else {
+ return (status_t)mHwc->blank(mHwc, disp,
+ mode == HWC_POWER_MODE_OFF ? 1 : 0);
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t HWComposer::setActiveConfig(int disp, int mode) {
+ LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE);
+ DisplayData& dd(mDisplayData[disp]);
+ dd.currentConfig = mode;
+ if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
+ return (status_t)mHwc->setActiveConfig(mHwc, disp, mode);
+ } else {
+ LOG_FATAL_IF(mode != 0);
+ }
+ return NO_ERROR;
+}
+
+void HWComposer::disconnectDisplay(int disp) {
+ LOG_ALWAYS_FATAL_IF(disp < 0 || disp == HWC_DISPLAY_PRIMARY);
+ DisplayData& dd(mDisplayData[disp]);
+ free(dd.list);
+ dd.list = NULL;
+ dd.framebufferTarget = NULL; // points into dd.list
+ dd.fbTargetHandle = NULL;
+ dd.outbufHandle = NULL;
+ dd.lastRetireFence = Fence::NO_FENCE;
+ dd.lastDisplayFence = Fence::NO_FENCE;
+ dd.outbufAcquireFence = Fence::NO_FENCE;
+ // clear all the previous configs and repopulate when a new
+ // device is added
+ dd.configs.clear();
+}
+
+int HWComposer::getVisualID() const {
+ if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
+ // is supported by the implementation. we can only be in this case
+ // if we have HWC 1.1
+ return HAL_PIXEL_FORMAT_RGBA_8888;
+ //return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ } else {
+ return mFbDev->format;
+ }
+}
+
+bool HWComposer::supportsFramebufferTarget() const {
+ return (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
+}
+
+int HWComposer::fbPost(int32_t id,
+ const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
+ if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ return setFramebufferTarget(id, acquireFence, buffer);
+ } else {
+ acquireFence->waitForever("HWComposer::fbPost");
+ return mFbDev->post(mFbDev, buffer->handle);
+ }
+}
+
+int HWComposer::fbCompositionComplete() {
+ if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
+ return NO_ERROR;
+
+ if (mFbDev->compositionComplete) {
+ return mFbDev->compositionComplete(mFbDev);
+ } else {
+ return INVALID_OPERATION;
+ }
+}
+
+void HWComposer::fbDump(String8& result) {
+ if (mFbDev && mFbDev->common.version >= 1 && mFbDev->dump) {
+ const size_t SIZE = 4096;
+ char buffer[SIZE];
+ mFbDev->dump(mFbDev, buffer, SIZE);
+ result.append(buffer);
+ }
+}
+
+status_t HWComposer::setOutputBuffer(int32_t id, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& buf) {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ return BAD_INDEX;
+ if (id < VIRTUAL_DISPLAY_ID_BASE)
+ return INVALID_OPERATION;
+
+ DisplayData& disp(mDisplayData[id]);
+ disp.outbufHandle = buf->handle;
+ disp.outbufAcquireFence = acquireFence;
+ return NO_ERROR;
+}
+
+sp<Fence> HWComposer::getLastRetireFence(int32_t id) const {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ return Fence::NO_FENCE;
+ return mDisplayData[id].lastRetireFence;
+}
+
+status_t HWComposer::setCursorPositionAsync(int32_t id, const Rect& pos)
+{
+ if (mHwc->setCursorPositionAsync) {
+ return (status_t)mHwc->setCursorPositionAsync(mHwc, id, pos.left, pos.top);
+ }
+ else {
+ return NO_ERROR;
+ }
+}
+
+/*
+ * Helper template to implement a concrete HWCLayer
+ * This holds the pointer to the concrete hwc layer type
+ * and implements the "iterable" side of HWCLayer.
+ */
+template<typename CONCRETE, typename HWCTYPE>
+class Iterable : public HWComposer::HWCLayer {
+protected:
+ HWCTYPE* const mLayerList;
+ HWCTYPE* mCurrentLayer;
+ explicit Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer),
+ mIndex(0) { }
+ inline HWCTYPE const * getLayer() const { return mCurrentLayer; }
+ inline HWCTYPE* getLayer() { return mCurrentLayer; }
+ virtual ~Iterable() { }
+ size_t mIndex;
+private:
+ // returns a copy of ourselves
+ virtual HWComposer::HWCLayer* dup() {
+ return new CONCRETE( static_cast<const CONCRETE&>(*this) );
+ }
+ virtual status_t setLayer(size_t index) {
+ mIndex = index;
+ mCurrentLayer = &mLayerList[index];
+ return NO_ERROR;
+ }
+};
+
+/*
+ * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0.
+ * This implements the HWCLayer side of HWCIterableLayer.
+ */
+class HWCLayerVersion1 : public Iterable<HWCLayerVersion1, hwc_layer_1_t> {
+ struct hwc_composer_device_1* mHwc;
+public:
+ HWCLayerVersion1(struct hwc_composer_device_1* hwc, hwc_layer_1_t* layer,
+ Vector<Region>* visibleRegions,
+ Vector<Region>* surfaceDamageRegions)
+ : Iterable<HWCLayerVersion1, hwc_layer_1_t>(layer), mHwc(hwc),
+ mVisibleRegions(visibleRegions),
+ mSurfaceDamageRegions(surfaceDamageRegions) {}
+
+ virtual int32_t getCompositionType() const {
+ return getLayer()->compositionType;
+ }
+ virtual uint32_t getHints() const {
+ return getLayer()->hints;
+ }
+ virtual sp<Fence> getAndResetReleaseFence() {
+ int fd = getLayer()->releaseFenceFd;
+ getLayer()->releaseFenceFd = -1;
+ return fd >= 0 ? new Fence(fd) : Fence::NO_FENCE;
+ }
+ virtual void setAcquireFenceFd(int fenceFd) {
+ getLayer()->acquireFenceFd = fenceFd;
+ }
+ virtual void setPerFrameDefaultState() {
+ //getLayer()->compositionType = HWC_FRAMEBUFFER;
+ }
+ virtual void setPlaneAlpha(uint8_t alpha) {
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
+ getLayer()->planeAlpha = alpha;
+ } else {
+ if (alpha < 0xFF) {
+ getLayer()->flags |= HWC_SKIP_LAYER;
+ }
+ }
+ }
+ virtual void setDefaultState() {
+ hwc_layer_1_t* const l = getLayer();
+ l->compositionType = HWC_FRAMEBUFFER;
+ l->hints = 0;
+ l->flags = HWC_SKIP_LAYER;
+ l->handle = 0;
+ l->transform = 0;
+ l->blending = HWC_BLENDING_NONE;
+ l->visibleRegionScreen.numRects = 0;
+ l->visibleRegionScreen.rects = NULL;
+ l->acquireFenceFd = -1;
+ l->releaseFenceFd = -1;
+ l->planeAlpha = 0xFF;
+ }
+ virtual void setSkip(bool skip) {
+ if (skip) {
+ getLayer()->flags |= HWC_SKIP_LAYER;
+ } else {
+ getLayer()->flags &= ~HWC_SKIP_LAYER;
+ }
+ }
+ virtual void setIsCursorLayerHint(bool isCursor) {
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
+ if (isCursor) {
+ getLayer()->flags |= HWC_IS_CURSOR_LAYER;
+ }
+ else {
+ getLayer()->flags &= ~HWC_IS_CURSOR_LAYER;
+ }
+ }
+ }
+ virtual void setBlending(uint32_t blending) {
+ getLayer()->blending = blending;
+ }
+ virtual void setTransform(uint32_t transform) {
+ getLayer()->transform = transform;
+ }
+ virtual void setFrame(const Rect& frame) {
+ getLayer()->displayFrame = reinterpret_cast<hwc_rect_t const&>(frame);
+ }
+ virtual void setCrop(const FloatRect& crop) {
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+ getLayer()->sourceCropf = reinterpret_cast<hwc_frect_t const&>(crop);
+ } else {
+ /*
+ * Since h/w composer didn't support a flot crop rect before version 1.3,
+ * using integer coordinates instead produces a different output from the GL code in
+ * Layer::drawWithOpenGL(). The difference can be large if the buffer crop to
+ * window size ratio is large and a window crop is defined
+ * (i.e.: if we scale the buffer a lot and we also crop it with a window crop).
+ */
+ hwc_rect_t& r = getLayer()->sourceCrop;
+ r.left = int(ceilf(crop.left));
+ r.top = int(ceilf(crop.top));
+ r.right = int(floorf(crop.right));
+ r.bottom= int(floorf(crop.bottom));
+ }
+ }
+ virtual void setVisibleRegionScreen(const Region& reg) {
+ hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen;
+ mVisibleRegions->editItemAt(mIndex) = reg;
+ visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(
+ mVisibleRegions->itemAt(mIndex).getArray(
+ &visibleRegion.numRects));
+ }
+ virtual void setSurfaceDamage(const Region& reg) {
+ if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_5)) {
+ return;
+ }
+ hwc_region_t& surfaceDamage = getLayer()->surfaceDamage;
+ // We encode default full-screen damage as INVALID_RECT upstream, but as
+ // 0 rects for HWComposer
+ if (reg.isRect() && reg.getBounds() == Rect::INVALID_RECT) {
+ surfaceDamage.numRects = 0;
+ surfaceDamage.rects = NULL;
+ return;
+ }
+ mSurfaceDamageRegions->editItemAt(mIndex) = reg;
+ surfaceDamage.rects = reinterpret_cast<hwc_rect_t const *>(
+ mSurfaceDamageRegions->itemAt(mIndex).getArray(
+ &surfaceDamage.numRects));
+ }
+ virtual void setSidebandStream(const sp<NativeHandle>& stream) {
+ ALOG_ASSERT(stream->handle() != NULL);
+ getLayer()->compositionType = HWC_SIDEBAND;
+ getLayer()->sidebandStream = stream->handle();
+ }
+ virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
+ if (buffer == 0 || buffer->handle == 0) {
+ getLayer()->compositionType = HWC_FRAMEBUFFER;
+ getLayer()->flags |= HWC_SKIP_LAYER;
+ getLayer()->handle = 0;
+ } else {
+ if (getLayer()->compositionType == HWC_SIDEBAND) {
+ // If this was a sideband layer but the stream was removed, reset
+ // it to FRAMEBUFFER. The HWC can change it to OVERLAY in prepare.
+ getLayer()->compositionType = HWC_FRAMEBUFFER;
+ }
+ getLayer()->handle = buffer->handle;
+ }
+ }
+ virtual void onDisplayed() {
+ getLayer()->acquireFenceFd = -1;
+ }
+
+protected:
+ // Pointers to the vectors of Region backing-memory held in DisplayData.
+ // Only the Region at mIndex corresponds to this Layer.
+ Vector<Region>* mVisibleRegions;
+ Vector<Region>* mSurfaceDamageRegions;
+};
+
+/*
+ * returns an iterator initialized at a given index in the layer list
+ */
+HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+ return LayerListIterator();
+ }
+ DisplayData& disp(mDisplayData[id]);
+ if (!mHwc || !disp.list || index > disp.list->numHwLayers) {
+ return LayerListIterator();
+ }
+ if (disp.visibleRegions.size() < disp.list->numHwLayers) {
+ disp.visibleRegions.resize(disp.list->numHwLayers);
+ }
+ if (disp.surfaceDamageRegions.size() < disp.list->numHwLayers) {
+ disp.surfaceDamageRegions.resize(disp.list->numHwLayers);
+ }
+ return LayerListIterator(new HWCLayerVersion1(mHwc, disp.list->hwLayers,
+ &disp.visibleRegions, &disp.surfaceDamageRegions), index);
+}
+
+/*
+ * returns an iterator on the beginning of the layer list
+ */
+HWComposer::LayerListIterator HWComposer::begin(int32_t id) {
+ return getLayerIterator(id, 0);
+}
+
+/*
+ * returns an iterator on the end of the layer list
+ */
+HWComposer::LayerListIterator HWComposer::end(int32_t id) {
+ size_t numLayers = 0;
+ if (uint32_t(id) <= 31 && mAllocatedDisplayIDs.hasBit(id)) {
+ const DisplayData& disp(mDisplayData[id]);
+ if (mHwc && disp.list) {
+ numLayers = disp.list->numHwLayers;
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+ // with HWC 1.1, the last layer is always the HWC_FRAMEBUFFER_TARGET,
+ // which we ignore when iterating through the layer list.
+ ALOGE_IF(!numLayers, "mDisplayData[%d].list->numHwLayers is 0", id);
+ if (numLayers) {
+ numLayers--;
+ }
+ }
+ }
+ }
+ return getLayerIterator(id, numLayers);
+}
+
+// Converts a PixelFormat to a human-readable string. Max 11 chars.
+// (Could use a table of prefab String8 objects.)
+static String8 getFormatStr(PixelFormat format) {
+ switch (format) {
+ case PIXEL_FORMAT_RGBA_8888: return String8("RGBA_8888");
+ case PIXEL_FORMAT_RGBX_8888: return String8("RGBx_8888");
+ case PIXEL_FORMAT_RGB_888: return String8("RGB_888");
+ case PIXEL_FORMAT_RGB_565: return String8("RGB_565");
+ case PIXEL_FORMAT_BGRA_8888: return String8("BGRA_8888");
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ return String8("ImplDef");
+ default:
+ String8 result;
+ result.appendFormat("? %08x", format);
+ return result;
+ }
+}
+
+void HWComposer::dump(String8& result) const {
+ Mutex::Autolock _l(mDisplayLock);
+ if (mHwc) {
+ result.appendFormat("Hardware Composer state (version %08x):\n", hwcApiVersion(mHwc));
+ result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ const DisplayData& disp(mDisplayData[i]);
+ if (!disp.connected)
+ continue;
+
+ const Vector< sp<Layer> >& visibleLayersSortedByZ =
+ mFlinger->getLayerSortedByZForHwcDisplay(i);
+
+
+ result.appendFormat(" Display[%zd] configurations (* current):\n", i);
+ for (size_t c = 0; c < disp.configs.size(); ++c) {
+ const DisplayConfig& config(disp.configs[c]);
+ result.appendFormat(" %s%zd: %ux%u, xdpi=%f, ydpi=%f"
+ ", refresh=%" PRId64 ", colorMode=%d\n",
+ c == disp.currentConfig ? "* " : "", c,
+ config.width, config.height, config.xdpi, config.ydpi,
+ config.refresh, config.colorMode);
+ }
+
+ if (disp.list) {
+ result.appendFormat(
+ " numHwLayers=%zu, flags=%08x\n",
+ disp.list->numHwLayers, disp.list->flags);
+
+ result.append(
+ " type | handle | hint | flag | tr | blnd | format | source crop (l,t,r,b) | frame | name \n"
+ "-----------+----------+------+------+----+------+-------------+--------------------------------+------------------------+------\n");
+ // " _________ | ________ | ____ | ____ | __ | ____ | ___________ |_____._,_____._,_____._,_____._ |_____,_____,_____,_____ | ___...
+ for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
+ const hwc_layer_1_t&l = disp.list->hwLayers[i];
+ int32_t format = -1;
+ String8 name("unknown");
+
+ if (i < visibleLayersSortedByZ.size()) {
+ const sp<Layer>& layer(visibleLayersSortedByZ[i]);
+ const sp<GraphicBuffer>& buffer(
+ layer->getActiveBuffer());
+ if (buffer != NULL) {
+ format = buffer->getPixelFormat();
+ }
+ name = layer->getName();
+ }
+
+ int type = l.compositionType;
+ if (type == HWC_FRAMEBUFFER_TARGET) {
+ name = "HWC_FRAMEBUFFER_TARGET";
+ format = disp.format;
+ }
+
+ static char const* compositionTypeName[] = {
+ "GLES",
+ "HWC",
+ "BKGND",
+ "FB TARGET",
+ "SIDEBAND",
+ "HWC_CURSOR",
+ "UNKNOWN"};
+ if (type >= NELEM(compositionTypeName))
+ type = NELEM(compositionTypeName) - 1;
+
+ String8 formatStr = getFormatStr(format);
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+ result.appendFormat(
+ " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7.1f,%7.1f,%7.1f,%7.1f |%5d,%5d,%5d,%5d | %s\n",
+ compositionTypeName[type],
+ intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(),
+ l.sourceCropf.left, l.sourceCropf.top, l.sourceCropf.right, l.sourceCropf.bottom,
+ l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
+ name.string());
+ } else {
+ result.appendFormat(
+ " %9s | %08" PRIxPTR " | %04x | %04x | %02x | %04x | %-11s |%7d,%7d,%7d,%7d |%5d,%5d,%5d,%5d | %s\n",
+ compositionTypeName[type],
+ intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, formatStr.string(),
+ l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
+ l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
+ name.string());
+ }
+ }
+ }
+ }
+ }
+
+ if (mHwc && mHwc->dump) {
+ const size_t SIZE = 4096;
+ char buffer[SIZE];
+ mHwc->dump(mHwc, buffer, SIZE);
+ result.append(buffer);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+HWComposer::VSyncThread::VSyncThread(HWComposer& hwc)
+ : mHwc(hwc), mEnabled(false),
+ mNextFakeVSync(0),
+ mRefreshPeriod(hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY))
+{
+}
+
+void HWComposer::VSyncThread::setEnabled(bool enabled) {
+ Mutex::Autolock _l(mLock);
+ if (mEnabled != enabled) {
+ mEnabled = enabled;
+ mCondition.signal();
+ }
+}
+
+void HWComposer::VSyncThread::onFirstRef() {
+ run("VSyncThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
+}
+
+bool HWComposer::VSyncThread::threadLoop() {
+ { // scope for lock
+ Mutex::Autolock _l(mLock);
+ while (!mEnabled) {
+ mCondition.wait(mLock);
+ }
+ }
+
+ const nsecs_t period = mRefreshPeriod;
+ const nsecs_t now = systemTime(CLOCK_MONOTONIC);
+ nsecs_t next_vsync = mNextFakeVSync;
+ nsecs_t sleep = next_vsync - now;
+ if (sleep < 0) {
+ // we missed, find where the next vsync should be
+ sleep = (period - ((now - next_vsync) % period));
+ next_vsync = now + sleep;
+ }
+ mNextFakeVSync = next_vsync + period;
+
+ struct timespec spec;
+ spec.tv_sec = next_vsync / 1000000000;
+ spec.tv_nsec = next_vsync % 1000000000;
+
+ int err;
+ do {
+ err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
+ } while (err<0 && errno == EINTR);
+
+ if (err == 0) {
+ mHwc.mEventHandler.onVSyncReceived(0, next_vsync);
+ }
+
+ return true;
+}
+
+HWComposer::DisplayData::DisplayData()
+: configs(),
+ currentConfig(0),
+ format(HAL_PIXEL_FORMAT_RGBA_8888),
+ connected(false),
+ hasFbComp(false), hasOvComp(false),
+ capacity(0), list(NULL),
+ framebufferTarget(NULL), fbTargetHandle(0),
+ lastRetireFence(Fence::NO_FENCE), lastDisplayFence(Fence::NO_FENCE),
+ outbufHandle(NULL), outbufAcquireFence(Fence::NO_FENCE),
+ events(0)
+{}
+
+HWComposer::DisplayData::~DisplayData() {
+ free(list);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
new file mode 100644
index 0000000..170e382
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SF_HWCOMPOSER_HWC1_H
+#define ANDROID_SF_HWCOMPOSER_HWC1_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware/hwcomposer_defs.h>
+
+#include <system/graphics.h>
+
+#include <ui/Fence.h>
+
+#include <utils/BitSet.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
+#include <utils/Thread.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
+extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
+ const struct timespec *request,
+ struct timespec *remain);
+
+struct hwc_composer_device_1;
+struct hwc_display_contents_1;
+struct hwc_layer_1;
+struct hwc_procs;
+struct framebuffer_device_t;
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Fence;
+class FloatRect;
+class GraphicBuffer;
+class NativeHandle;
+class Region;
+class String8;
+class SurfaceFlinger;
+
+class HWComposer
+{
+public:
+ class EventHandler {
+ friend class HWComposer;
+ virtual void onVSyncReceived(int disp, nsecs_t timestamp) = 0;
+ virtual void onHotplugReceived(int disp, bool connected) = 0;
+ protected:
+ virtual ~EventHandler() {}
+ };
+
+ enum {
+ NUM_BUILTIN_DISPLAYS = HWC_NUM_PHYSICAL_DISPLAY_TYPES,
+ MAX_HWC_DISPLAYS = HWC_NUM_DISPLAY_TYPES,
+ VIRTUAL_DISPLAY_ID_BASE = HWC_DISPLAY_VIRTUAL,
+ };
+
+ HWComposer(
+ const sp<SurfaceFlinger>& flinger,
+ EventHandler& handler);
+
+ ~HWComposer();
+
+ status_t initCheck() const;
+
+ // Returns a display ID starting at VIRTUAL_DISPLAY_ID_BASE, this ID is to
+ // be used with createWorkList (and all other methods requiring an ID
+ // below).
+ // IDs below NUM_BUILTIN_DISPLAYS are pre-defined and therefore are
+ // always valid.
+ // Returns -1 if an ID cannot be allocated
+ int32_t allocateDisplayId();
+
+ // Recycles the given virtual display ID and frees the associated worklist.
+ // IDs below NUM_BUILTIN_DISPLAYS are not recycled.
+ status_t freeDisplayId(int32_t id);
+
+
+ // Asks the HAL what it can do
+ status_t prepare();
+
+ // commits the list
+ status_t commit();
+
+ // set power mode
+ status_t setPowerMode(int disp, int mode);
+
+ // set active config
+ status_t setActiveConfig(int disp, int mode);
+
+ // reset state when an external, non-virtual display is disconnected
+ void disconnectDisplay(int disp);
+
+ // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
+ status_t createWorkList(int32_t id, size_t numLayers);
+
+ bool supportsFramebufferTarget() const;
+
+ // does this display have layers handled by HWC
+ bool hasHwcComposition(int32_t id) const;
+
+ // does this display have layers handled by GLES
+ bool hasGlesComposition(int32_t id) const;
+
+ // get the releaseFence file descriptor for a display's framebuffer layer.
+ // the release fence is only valid after commit()
+ sp<Fence> getAndResetReleaseFence(int32_t id);
+
+ // needed forward declarations
+ class LayerListIterator;
+
+ // return the visual id to be used to find a suitable EGLConfig for
+ // *ALL* displays.
+ int getVisualID() const;
+
+ // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface).
+ int fbPost(int32_t id, const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
+ int fbCompositionComplete();
+ void fbDump(String8& result);
+
+ // Set the output buffer and acquire fence for a virtual display.
+ // Returns INVALID_OPERATION if id is not a virtual display.
+ status_t setOutputBuffer(int32_t id, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& buf);
+
+ // Get the retire fence for the last committed frame. This fence will
+ // signal when the h/w composer is completely finished with the frame.
+ // For physical displays, it is no longer being displayed. For virtual
+ // displays, writes to the output buffer are complete.
+ sp<Fence> getLastRetireFence(int32_t id) const;
+
+ status_t setCursorPositionAsync(int32_t id, const Rect &pos);
+
+ /*
+ * Interface to hardware composer's layers functionality.
+ * This abstracts the HAL interface to layers which can evolve in
+ * incompatible ways from one release to another.
+ * The idea is that we could extend this interface as we add
+ * features to h/w composer.
+ */
+ class HWCLayerInterface {
+ protected:
+ virtual ~HWCLayerInterface() { }
+ public:
+ virtual int32_t getCompositionType() const = 0;
+ virtual uint32_t getHints() const = 0;
+ virtual sp<Fence> getAndResetReleaseFence() = 0;
+ virtual void setDefaultState() = 0;
+ virtual void setSkip(bool skip) = 0;
+ virtual void setIsCursorLayerHint(bool isCursor = true) = 0;
+ virtual void setBlending(uint32_t blending) = 0;
+ virtual void setTransform(uint32_t transform) = 0;
+ virtual void setFrame(const Rect& frame) = 0;
+ virtual void setCrop(const FloatRect& crop) = 0;
+ virtual void setVisibleRegionScreen(const Region& reg) = 0;
+ virtual void setSurfaceDamage(const Region& reg) = 0;
+ virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0;
+ virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
+ virtual void setAcquireFenceFd(int fenceFd) = 0;
+ virtual void setPlaneAlpha(uint8_t alpha) = 0;
+ virtual void onDisplayed() = 0;
+ };
+
+ /*
+ * Interface used to implement an iterator to a list
+ * of HWCLayer.
+ */
+ class HWCLayer : public HWCLayerInterface {
+ friend class LayerListIterator;
+ // select the layer at the given index
+ virtual status_t setLayer(size_t index) = 0;
+ virtual HWCLayer* dup() = 0;
+ static HWCLayer* copy(HWCLayer *rhs) {
+ return rhs ? rhs->dup() : NULL;
+ }
+ protected:
+ virtual ~HWCLayer() { }
+ };
+
+ /*
+ * Iterator through a HWCLayer list.
+ * This behaves more or less like a forward iterator.
+ */
+ class LayerListIterator {
+ friend class HWComposer;
+ HWCLayer* const mLayerList;
+ size_t mIndex;
+
+ LayerListIterator() : mLayerList(NULL), mIndex(0) { }
+
+ LayerListIterator(HWCLayer* layer, size_t index)
+ : mLayerList(layer), mIndex(index) { }
+
+ // we don't allow assignment, because we don't need it for now
+ LayerListIterator& operator = (const LayerListIterator& rhs);
+
+ public:
+ // copy operators
+ LayerListIterator(const LayerListIterator& rhs)
+ : mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) {
+ }
+
+ ~LayerListIterator() { delete mLayerList; }
+
+ // pre-increment
+ LayerListIterator& operator++() {
+ mLayerList->setLayer(++mIndex);
+ return *this;
+ }
+
+ // dereference
+ HWCLayerInterface& operator * () { return *mLayerList; }
+ HWCLayerInterface* operator -> () { return mLayerList; }
+
+ // comparison
+ bool operator == (const LayerListIterator& rhs) const {
+ return mIndex == rhs.mIndex;
+ }
+ bool operator != (const LayerListIterator& rhs) const {
+ return !operator==(rhs);
+ }
+ };
+
+ // Returns an iterator to the beginning of the layer list
+ LayerListIterator begin(int32_t id);
+
+ // Returns an iterator to the end of the layer list
+ LayerListIterator end(int32_t id);
+
+
+ // Events handling ---------------------------------------------------------
+
+ enum {
+ EVENT_VSYNC = HWC_EVENT_VSYNC
+ };
+
+ void eventControl(int disp, int event, int enabled);
+
+ struct DisplayConfig {
+ uint32_t width;
+ uint32_t height;
+ float xdpi;
+ float ydpi;
+ nsecs_t refresh;
+ android_color_mode_t colorMode;
+ bool operator==(const DisplayConfig& rhs) const {
+ return width == rhs.width &&
+ height == rhs.height &&
+ xdpi == rhs.xdpi &&
+ ydpi == rhs.ydpi &&
+ refresh == rhs.refresh &&
+ colorMode == rhs.colorMode;
+ }
+ };
+
+ // Query display parameters. Pass in a display index (e.g.
+ // HWC_DISPLAY_PRIMARY).
+ nsecs_t getRefreshTimestamp(int disp) const;
+ sp<Fence> getDisplayFence(int disp) const;
+ uint32_t getFormat(int disp) const;
+ bool isConnected(int disp) const;
+
+ // These return the values for the current config of a given display index.
+ // To get the values for all configs, use getConfigs below.
+ uint32_t getWidth(int disp) const;
+ uint32_t getHeight(int disp) const;
+ float getDpiX(int disp) const;
+ float getDpiY(int disp) const;
+ nsecs_t getRefreshPeriod(int disp) const;
+ android_color_mode_t getColorMode(int disp) const;
+
+ const Vector<DisplayConfig>& getConfigs(int disp) const;
+ size_t getCurrentConfig(int disp) const;
+
+ status_t setVirtualDisplayProperties(int32_t id, uint32_t w, uint32_t h,
+ uint32_t format);
+
+ // this class is only used to fake the VSync event on systems that don't
+ // have it.
+ class VSyncThread : public Thread {
+ HWComposer& mHwc;
+ mutable Mutex mLock;
+ Condition mCondition;
+ bool mEnabled;
+ mutable nsecs_t mNextFakeVSync;
+ nsecs_t mRefreshPeriod;
+ virtual void onFirstRef();
+ virtual bool threadLoop();
+ public:
+ VSyncThread(HWComposer& hwc);
+ void setEnabled(bool enabled);
+ };
+
+ friend class VSyncThread;
+
+ // for debugging ----------------------------------------------------------
+ void dump(String8& out) const;
+
+private:
+ void loadHwcModule();
+ int loadFbHalModule();
+
+ LayerListIterator getLayerIterator(int32_t id, size_t index);
+
+ struct cb_context;
+
+ static void hook_invalidate(const struct hwc_procs* procs);
+ static void hook_vsync(const struct hwc_procs* procs, int disp,
+ int64_t timestamp);
+ static void hook_hotplug(const struct hwc_procs* procs, int disp,
+ int connected);
+
+ inline void invalidate();
+ inline void vsync(int disp, int64_t timestamp);
+ inline void hotplug(int disp, int connected);
+
+ status_t queryDisplayProperties(int disp);
+
+ status_t setFramebufferTarget(int32_t id,
+ const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
+
+ struct DisplayData {
+ DisplayData();
+ ~DisplayData();
+ Vector<DisplayConfig> configs;
+ size_t currentConfig;
+ uint32_t format; // pixel format from FB hal, for pre-hwc-1.1
+ bool connected;
+ bool hasFbComp;
+ bool hasOvComp;
+ size_t capacity;
+ hwc_display_contents_1* list;
+ hwc_layer_1* framebufferTarget;
+ buffer_handle_t fbTargetHandle;
+ sp<Fence> lastRetireFence; // signals when the last set op retires
+ sp<Fence> lastDisplayFence; // signals when the last set op takes
+ // effect on screen
+ buffer_handle_t outbufHandle;
+ sp<Fence> outbufAcquireFence;
+
+ // protected by mEventControlLock
+ int32_t events;
+
+ // We need to hold "copies" of these for memory management purposes. The
+ // actual hwc_layer_1_t holds pointers to the memory within. Vector<>
+ // internally doesn't copy the memory unless one of the copies is
+ // modified.
+ Vector<Region> visibleRegions;
+ Vector<Region> surfaceDamageRegions;
+ };
+
+ sp<SurfaceFlinger> mFlinger;
+ framebuffer_device_t* mFbDev;
+ struct hwc_composer_device_1* mHwc;
+ // invariant: mLists[0] != NULL iff mHwc != NULL
+ // mLists[i>0] can be NULL. that display is to be ignored
+ struct hwc_display_contents_1* mLists[MAX_HWC_DISPLAYS];
+ DisplayData mDisplayData[MAX_HWC_DISPLAYS];
+ // protect mDisplayData from races between prepare and dump
+ mutable Mutex mDisplayLock;
+ size_t mNumDisplays;
+
+ cb_context* mCBContext;
+ EventHandler& mEventHandler;
+ size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
+ sp<VSyncThread> mVSyncThread;
+ bool mDebugForceFakeVSync;
+ BitSet32 mAllocatedDisplayIDs;
+
+ // protected by mLock
+ mutable Mutex mLock;
+ mutable nsecs_t mLastHwVSync[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
+
+ // thread-safe
+ mutable Mutex mEventControlLock;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index a9271c2..2190466 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -175,6 +175,12 @@
return NO_ERROR;
}
+#ifndef USE_HWC2
+status_t VirtualDisplaySurface::compositionComplete() {
+ return NO_ERROR;
+}
+#endif
+
status_t VirtualDisplaySurface::advanceFrame() {
if (mDisplayId < 0)
return NO_ERROR;
@@ -214,9 +220,13 @@
status_t result = NO_ERROR;
if (fbBuffer != NULL) {
+#ifdef USE_HWC2
// TODO: Correctly propagate the dataspace from GL composition
result = mHwc.setClientTarget(mDisplayId, mFbFence, fbBuffer,
HAL_DATASPACE_UNKNOWN);
+#else
+ result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
+#endif
}
return result;
@@ -230,14 +240,22 @@
"Unexpected onFrameCommitted() in %s state", dbgStateStr());
mDbgState = DBG_STATE_IDLE;
+#ifdef USE_HWC2
sp<Fence> retireFence = mHwc.getRetireFence(mDisplayId);
+#else
+ sp<Fence> fbFence = mHwc.getAndResetReleaseFence(mDisplayId);
+#endif
if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) {
// release the scratch buffer back to the pool
Mutex::Autolock lock(mMutex);
int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot);
VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot);
+#ifdef USE_HWC2
addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot],
retireFence);
+#else
+ addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence);
+#endif
releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot],
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
}
@@ -245,6 +263,9 @@
if (mOutputProducerSlot >= 0) {
int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot);
QueueBufferOutput qbo;
+#ifndef USE_HWC2
+ sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId);
+#endif
VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot);
if (mMustRecompose) {
status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
@@ -253,7 +274,11 @@
HAL_DATASPACE_UNKNOWN,
Rect(mSinkBufferWidth, mSinkBufferHeight),
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */,
+#ifdef USE_HWC2
retireFence),
+#else
+ outFence),
+#endif
&qbo);
if (result == NO_ERROR) {
updateQueueBufferOutput(qbo);
@@ -263,7 +288,11 @@
// through the motions of updating the display to keep our state
// machine happy. We cancel the buffer to avoid triggering another
// re-composition and causing an infinite loop.
+#ifdef USE_HWC2
mSource[SOURCE_SINK]->cancelBuffer(sslot, retireFence);
+#else
+ mSource[SOURCE_SINK]->cancelBuffer(sslot, outFence);
+#endif
}
}
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 884460d..70f717f 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -83,6 +83,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;