summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/gui/BufferItemConsumer.h91
-rw-r--r--include/gui/CpuConsumer.h4
-rw-r--r--include/ui/Fence.h3
-rw-r--r--include/utils/VectorImpl.h20
-rw-r--r--libs/gui/Android.mk3
-rw-r--r--libs/gui/BufferItemConsumer.cpp93
-rw-r--r--libs/gui/CpuConsumer.cpp3
-rw-r--r--libs/utils/VectorImpl.cpp19
-rw-r--r--services/surfaceflinger/DisplayDevice.cpp4
-rw-r--r--services/surfaceflinger/DisplayDevice.h12
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp558
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.h65
-rw-r--r--services/surfaceflinger/EventThread.cpp184
-rw-r--r--services/surfaceflinger/EventThread.h5
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp73
15 files changed, 608 insertions, 529 deletions
diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h
new file mode 100644
index 0000000..cd4df25
--- /dev/null
+++ b/include/gui/BufferItemConsumer.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 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_GUI_BUFFERITEMCONSUMER_H
+#define ANDROID_GUI_BUFFERITEMCONSUMER_H
+
+#include <gui/ConsumerBase.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+#define ANDROID_GRAPHICS_BUFFERITEMCONSUMER_JNI_ID "mBufferItemConsumer"
+
+namespace android {
+
+/**
+ * BufferItemConsumer is a BufferQueue consumer endpoint that allows clients
+ * access to the whole BufferItem entry from BufferQueue. Multiple buffers may
+ * be acquired at once, to be used concurrently by the client. This consumer can
+ * operate either in synchronous or asynchronous mode.
+ */
+class BufferItemConsumer: public ConsumerBase
+{
+ public:
+ typedef ConsumerBase::FrameAvailableListener FrameAvailableListener;
+
+ typedef BufferQueue::BufferItem BufferItem;
+
+ enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT };
+ enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE };
+
+ // Create a new buffer item consumer. The consumerUsage parameter determines
+ // the consumer usage flags passed to the graphics allocator. The
+ // bufferCount parameter specifies how many buffers can be locked for user
+ // access at the same time.
+ BufferItemConsumer(uint32_t consumerUsage,
+ int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS,
+ bool synchronousMode = false);
+
+ virtual ~BufferItemConsumer();
+
+ // set the name of the BufferItemConsumer that will be used to identify it in
+ // log messages.
+ void setName(const String8& name);
+
+ // Gets the next graphics buffer from the producer, filling out the
+ // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue
+ // of buffers is empty, and INVALID_OPERATION if the maximum number of
+ // buffers is already acquired.
+ //
+ // Only a fixed number of buffers can be acquired at a time, determined by
+ // the construction-time bufferCount parameter. If INVALID_OPERATION is
+ // returned by acquireBuffer, then old buffers must be returned to the
+ // queue by calling releaseBuffer before more buffers can be acquired.
+ //
+ // If waitForFence is true, and the acquired BufferItem has a valid fence object,
+ // acquireBuffer will wait on the fence with no timeout before returning.
+ status_t acquireBuffer(BufferItem *item, bool waitForFence = true);
+
+ // Returns an acquired buffer to the queue, allowing it to be reused. Since
+ // only a fixed number of buffers may be acquired at a time, old buffers
+ // must be released by calling releaseBuffer to ensure new buffers can be
+ // acquired by acquireBuffer. Once a BufferItem is released, the caller must
+ // not access any members of the BufferItem, and should immediately remove
+ // all of its references to the BufferItem itself.
+ status_t releaseBuffer(const BufferItem &item,
+ const sp<Fence>& releaseFence = Fence::NO_FENCE);
+
+ sp<ISurfaceTexture> getProducerInterface() const { return getBufferQueue(); }
+
+};
+
+} // namespace android
+
+#endif // ANDROID_GUI_CPUCONSUMER_H
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
index 49c90db..807a4b5 100644
--- a/include/gui/CpuConsumer.h
+++ b/include/gui/CpuConsumer.h
@@ -59,6 +59,8 @@ class CpuConsumer: public ConsumerBase
// how many buffers can be locked for user access at the same time.
CpuConsumer(uint32_t maxLockedBuffers);
+ virtual ~CpuConsumer();
+
// set the name of the CpuConsumer that will be used to identify it in
// log messages.
void setName(const String8& name);
@@ -86,7 +88,7 @@ class CpuConsumer: public ConsumerBase
// Maximum number of buffers that can be locked at a time
uint32_t mMaxLockedBuffers;
- void freeBufferLocked(int slotIndex);
+ virtual void freeBufferLocked(int slotIndex);
// Array for tracking pointers passed to the consumer, matching the
// mSlots indexing
diff --git a/include/ui/Fence.h b/include/ui/Fence.h
index 17cb018..b516a22 100644
--- a/include/ui/Fence.h
+++ b/include/ui/Fence.h
@@ -18,7 +18,6 @@
#define ANDROID_FENCE_H
#include <stdint.h>
-#include <limits.h>
#include <sys/types.h>
#include <ui/ANativeObjectBase.h>
@@ -65,7 +64,7 @@ public:
// TIMEOUT_NEVER may be passed to the wait method to indicate that it
// should wait indefinitely for the fence to signal.
- enum { TIMEOUT_NEVER = UINT_MAX };
+ enum { TIMEOUT_NEVER = -1 };
// merge combines two Fence objects, creating a new Fence object that
// becomes signaled when both f1 and f2 are signaled (even if f1 or f2 is
diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h
index b1224c6..c4ec2ff 100644
--- a/include/utils/VectorImpl.h
+++ b/include/utils/VectorImpl.h
@@ -104,6 +104,16 @@ protected:
virtual void do_splat(void* dest, const void* item, size_t num) const = 0;
virtual void do_move_forward(void* dest, const void* from, size_t num) const = 0;
virtual void do_move_backward(void* dest, const void* from, size_t num) const = 0;
+
+ // take care of FBC...
+ virtual void reservedVectorImpl1();
+ virtual void reservedVectorImpl2();
+ virtual void reservedVectorImpl3();
+ virtual void reservedVectorImpl4();
+ virtual void reservedVectorImpl5();
+ virtual void reservedVectorImpl6();
+ virtual void reservedVectorImpl7();
+ virtual void reservedVectorImpl8();
private:
void* _grow(size_t where, size_t amount);
@@ -155,6 +165,16 @@ public:
protected:
virtual int do_compare(const void* lhs, const void* rhs) const = 0;
+ // take care of FBC...
+ virtual void reservedSortedVectorImpl1();
+ virtual void reservedSortedVectorImpl2();
+ virtual void reservedSortedVectorImpl3();
+ virtual void reservedSortedVectorImpl4();
+ virtual void reservedSortedVectorImpl5();
+ virtual void reservedSortedVectorImpl6();
+ virtual void reservedSortedVectorImpl7();
+ virtual void reservedSortedVectorImpl8();
+
private:
ssize_t _indexOrderOf(const void* item, size_t* order = 0) const;
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 3aa3a50..2bf363f 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -23,7 +23,8 @@ LOCAL_SRC_FILES:= \
Surface.cpp \
SurfaceComposerClient.cpp \
DummyConsumer.cpp \
- CpuConsumer.cpp
+ CpuConsumer.cpp \
+ BufferItemConsumer.cpp
LOCAL_SHARED_LIBRARIES := \
libbinder \
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
new file mode 100644
index 0000000..218d929
--- /dev/null
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2012 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 LOG_NDEBUG 0
+#define LOG_TAG "BufferItemConsumer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <utils/Log.h>
+
+#include <gui/BufferItemConsumer.h>
+
+#define BI_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+
+namespace android {
+
+BufferItemConsumer::BufferItemConsumer(uint32_t consumerUsage,
+ int bufferCount, bool synchronousMode) :
+ ConsumerBase(new BufferQueue(true, bufferCount) )
+{
+ mBufferQueue->setConsumerUsageBits(consumerUsage);
+ mBufferQueue->setSynchronousMode(synchronousMode);
+}
+
+BufferItemConsumer::~BufferItemConsumer() {
+}
+
+void BufferItemConsumer::setName(const String8& name) {
+ Mutex::Autolock _l(mMutex);
+ mName = name;
+ mBufferQueue->setConsumerName(name);
+}
+
+status_t BufferItemConsumer::acquireBuffer(BufferItem *item, bool waitForFence) {
+ status_t err;
+
+ if (!item) return BAD_VALUE;
+
+ Mutex::Autolock _l(mMutex);
+
+ err = acquireBufferLocked(item);
+ if (err != OK) {
+ if (err != NO_BUFFER_AVAILABLE) {
+ BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
+ }
+ return err;
+ }
+
+ if (waitForFence && item->mFence.get()) {
+ err = item->mFence->wait(Fence::TIMEOUT_NEVER);
+ if (err != OK) {
+ BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
+ strerror(-err), err);
+ return err;
+ }
+ }
+
+ item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer;
+
+ return OK;
+}
+
+status_t BufferItemConsumer::releaseBuffer(const BufferItem &item,
+ const sp<Fence>& releaseFence) {
+ status_t err;
+
+ Mutex::Autolock _l(mMutex);
+
+ err = releaseBufferLocked(item.mBuf, EGL_NO_DISPLAY,
+ EGL_NO_SYNC_KHR, releaseFence);
+ if (err != OK) {
+ BI_LOGE("Failed to release buffer: %s (%d)",
+ strerror(-err), err);
+ }
+ return err;
+}
+
+} // namespace android
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 90c8ea6..242ac45 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -43,6 +43,9 @@ CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers) :
mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
}
+CpuConsumer::~CpuConsumer() {
+}
+
void CpuConsumer::setName(const String8& name) {
Mutex::Autolock _l(mMutex);
mName = name;
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
index 020ec15..3855305 100644
--- a/libs/utils/VectorImpl.cpp
+++ b/libs/utils/VectorImpl.cpp
@@ -494,6 +494,15 @@ void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) con
do_move_backward(dest, from, num);
}
+void VectorImpl::reservedVectorImpl1() { }
+void VectorImpl::reservedVectorImpl2() { }
+void VectorImpl::reservedVectorImpl3() { }
+void VectorImpl::reservedVectorImpl4() { }
+void VectorImpl::reservedVectorImpl5() { }
+void VectorImpl::reservedVectorImpl6() { }
+void VectorImpl::reservedVectorImpl7() { }
+void VectorImpl::reservedVectorImpl8() { }
+
/*****************************************************************************/
SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags)
@@ -609,6 +618,16 @@ ssize_t SortedVectorImpl::remove(const void* item)
return i;
}
+void SortedVectorImpl::reservedSortedVectorImpl1() { };
+void SortedVectorImpl::reservedSortedVectorImpl2() { };
+void SortedVectorImpl::reservedSortedVectorImpl3() { };
+void SortedVectorImpl::reservedSortedVectorImpl4() { };
+void SortedVectorImpl::reservedSortedVectorImpl5() { };
+void SortedVectorImpl::reservedSortedVectorImpl6() { };
+void SortedVectorImpl::reservedSortedVectorImpl7() { };
+void SortedVectorImpl::reservedSortedVectorImpl8() { };
+
+
/*****************************************************************************/
}; // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 2289444..821a329 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -68,12 +68,12 @@ void checkGLErrors()
DisplayDevice::DisplayDevice(
const sp<SurfaceFlinger>& flinger,
- int display,
+ int32_t display, int32_t hwcDisplayId,
const sp<ANativeWindow>& nativeWindow,
const sp<FramebufferSurface>& framebufferSurface,
EGLConfig config)
: mFlinger(flinger),
- mId(display),
+ mId(display), mHwcDisplayId(hwcDisplayId),
mNativeWindow(nativeWindow),
mFramebufferSurface(framebufferSurface),
mDisplay(EGL_NO_DISPLAY),
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 9790699..ea56d90 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -28,6 +28,8 @@
#include <utils/Mutex.h>
#include <utils/Timers.h>
+#include <hardware/hwcomposer_defs.h>
+
#include "Transform.h"
struct ANativeWindow;
@@ -50,9 +52,9 @@ public:
Region undefinedRegion;
enum {
- DISPLAY_ID_MAIN = 0,
- DISPLAY_ID_HDMI = 1,
- DISPLAY_ID_COUNT
+ DISPLAY_ID_MAIN = HWC_DISPLAY_PRIMARY,
+ DISPLAY_ID_HDMI = HWC_DISPLAY_EXTERNAL,
+ DISPLAY_ID_COUNT = HWC_NUM_DISPLAY_TYPES
};
enum {
@@ -62,7 +64,7 @@ public:
DisplayDevice(
const sp<SurfaceFlinger>& flinger,
- int dpy,
+ int32_t dpy, int32_t hwcDisplayId,
const sp<ANativeWindow>& nativeWindow,
const sp<FramebufferSurface>& framebufferSurface,
EGLConfig config);
@@ -96,6 +98,7 @@ public:
const Transform& getTransform() const { return mGlobalTransform; }
uint32_t getLayerStack() const { return mLayerStack; }
int32_t getDisplayId() const { return mId; }
+ int32_t getHwcDisplayId() const { return mHwcDisplayId; }
status_t compositionComplete() const;
@@ -132,6 +135,7 @@ private:
*/
sp<SurfaceFlinger> mFlinger;
int32_t mId;
+ int32_t mHwcDisplayId;
// ANativeWindow this display is rendering into
sp<ANativeWindow> mNativeWindow;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index a3ec352..b1f8328 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -17,7 +17,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
// Uncomment this to remove support for HWC_DEVICE_API_VERSION_0_3 and older
-// #define HWC_REMOVE_DEPRECATED_VERSIONS 1
+#define HWC_REMOVE_DEPRECATED_VERSIONS 1
#include <stdint.h>
#include <stdio.h>
@@ -46,120 +46,8 @@
namespace android {
-// ---------------------------------------------------------------------------
-// Support for HWC_DEVICE_API_VERSION_0_3 and older:
-// Since v0.3 is deprecated and support will be dropped soon, as much as
-// possible the code is written to target v1.0. When using a v0.3 HWC, we
-// allocate v0.3 structures, but assign them to v1.0 pointers.
-
-#if HWC_REMOVE_DEPRECATED_VERSIONS
-// We need complete types to satisfy semantic checks, even though the code
-// paths that use these won't get executed at runtime (and will likely be dead-
-// code-eliminated). When we remove the code to support v0.3 we can remove
-// these as well.
-typedef hwc_layer_1_t hwc_layer_t;
-typedef hwc_display_contents_1_t hwc_layer_list_t;
-typedef hwc_composer_device_1_t hwc_composer_device_t;
-#endif
-
-// This function assumes we've already rejected HWC's with lower-than-required
-// versions. Don't use it for the initial "does HWC meet requirements" check!
static bool hwcHasVersion(const hwc_composer_device_1_t* hwc, uint32_t version) {
- if (HWC_REMOVE_DEPRECATED_VERSIONS &&
- version <= HWC_DEVICE_API_VERSION_1_0) {
- return true;
- } else {
- return hwc->common.version >= version;
- }
-}
-
-static bool hwcHasVsyncEvent(const hwc_composer_device_1_t* hwc) {
- return hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_0_3);
-}
-
-static size_t sizeofHwcLayerList(const hwc_composer_device_1_t* hwc,
- size_t numLayers) {
- if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
- return sizeof(hwc_display_contents_1_t) + numLayers*sizeof(hwc_layer_1_t);
- } else {
- return sizeof(hwc_layer_list_t) + numLayers*sizeof(hwc_layer_t);
- }
-}
-
-static int hwcEventControl(hwc_composer_device_1_t* hwc, int dpy,
- int event, int enabled) {
- if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
- return hwc->methods->eventControl(hwc, dpy, event, enabled);
- } else {
- hwc_composer_device_t* hwc0 = reinterpret_cast<hwc_composer_device_t*>(hwc);
- return hwc0->methods->eventControl(hwc0, event, enabled);
- }
-}
-
-static int hwcBlank(hwc_composer_device_1_t* hwc, int dpy, int blank) {
- if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
- return hwc->methods->blank(hwc, dpy, blank);
- } else {
- if (blank) {
- hwc_composer_device_t* hwc0 = reinterpret_cast<hwc_composer_device_t*>(hwc);
- return hwc0->set(hwc0, NULL, NULL, NULL);
- } else {
- // HWC 0.x turns the screen on at the next set()
- return NO_ERROR;
- }
- }
-}
-
-static int hwcPrepare(hwc_composer_device_1_t* hwc,
- size_t numDisplays, hwc_display_contents_1_t** displays) {
- if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
- return hwc->prepare(hwc, numDisplays, displays);
- } else {
- hwc_composer_device_t* hwc0 = reinterpret_cast<hwc_composer_device_t*>(hwc);
- hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(displays[0]);
- // In the past, SurfaceFlinger would pass a NULL list when doing full
- // OpenGL ES composition. I don't know what, if any, dependencies there
- // are on this behavior, so I'm playing it safe and preserving it.
- if (list0->numHwLayers == 0)
- return hwc0->prepare(hwc0, NULL);
- else
- return hwc0->prepare(hwc0, list0);
- }
-}
-
-static int hwcSet(hwc_composer_device_1_t* hwc, EGLDisplay dpy, EGLSurface sur,
- size_t numDisplays, hwc_display_contents_1_t** displays) {
- int err;
- if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
- displays[0]->dpy = dpy;
- displays[0]->sur = sur;
- err = hwc->set(hwc, numDisplays, displays);
- } else {
- hwc_composer_device_t* hwc0 = reinterpret_cast<hwc_composer_device_t*>(hwc);
- hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(displays[0]);
- err = hwc0->set(hwc0, dpy, sur, list0);
- }
- return err;
-}
-
-static uint32_t& hwcFlags(hwc_composer_device_1_t* hwc,
- hwc_display_contents_1_t* display) {
- if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
- return display->flags;
- } else {
- hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(display);
- return list0->flags;
- }
-}
-
-static size_t& hwcNumHwLayers(hwc_composer_device_1_t* hwc,
- hwc_display_contents_1_t* display) {
- if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
- return display->numHwLayers;
- } else {
- hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(display);
- return list0->numHwLayers;
- }
+ return hwc->common.version >= version;
}
// ---------------------------------------------------------------------------
@@ -182,14 +70,14 @@ HWComposer::HWComposer(
EventHandler& handler,
framebuffer_device_t const* fbDev)
: mFlinger(flinger),
- mModule(0), mHwc(0), mCapacity(0),
- mNumOVLayers(0), mNumFBLayers(0),
+ mModule(0), mHwc(0), mNumDisplays(1),
mCBContext(new cb_context),
- mEventHandler(handler), mRefreshPeriod(0),
+ mEventHandler(handler),
mVSyncCount(0), mDebugForceFakeVSync(false)
{
- for (size_t i = 0; i < MAX_DISPLAYS; i++)
- mLists[i] = NULL;
+ for (size_t i =0 ; i<MAX_DISPLAYS ; i++) {
+ mLists[i] = 0;
+ }
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.no_hw_vsync", value, "0");
@@ -203,8 +91,7 @@ HWComposer::HWComposer(
ALOGE_IF(err, "%s device failed to initialize (%s)",
HWC_HARDWARE_COMPOSER, strerror(-err));
if (err == 0) {
- if (HWC_REMOVE_DEPRECATED_VERSIONS &&
- mHwc->common.version < HWC_DEVICE_API_VERSION_1_0) {
+ if (mHwc->common.version < HWC_DEVICE_API_VERSION_1_0) {
ALOGE("%s device version %#x too old, will not be used",
HWC_HARDWARE_COMPOSER, mHwc->common.version);
hwc_close_1(mHwc);
@@ -213,45 +100,54 @@ HWComposer::HWComposer(
}
if (mHwc) {
- // always turn vsync off when we start
- needVSyncThread = false;
- if (hwcHasVsyncEvent(mHwc)) {
- hwcEventControl(mHwc, 0, HWC_EVENT_VSYNC, 0);
-
- int period;
- if (mHwc->query(mHwc, HWC_VSYNC_PERIOD, &period) == NO_ERROR) {
- mRefreshPeriod = nsecs_t(period);
- }
- } else {
- needVSyncThread = true;
- }
-
if (mHwc->registerProcs) {
mCBContext->hwc = this;
mCBContext->procs.invalidate = &hook_invalidate;
mCBContext->procs.vsync = &hook_vsync;
- mHwc->registerProcs(mHwc, &mCBContext->procs);
memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
+ mHwc->registerProcs(mHwc, &mCBContext->procs);
}
- // create initial empty display contents for display 0
- createWorkList(MAIN, 0);
- }
- }
+ // always turn vsync off when we start
+ needVSyncThread = false;
+ mHwc->eventControl(mHwc, 0, HWC_EVENT_VSYNC, 0);
+ int period;
+ if (mHwc->query(mHwc, HWC_VSYNC_PERIOD, &period) == NO_ERROR) {
+ mDisplayData[HWC_DISPLAY_PRIMARY].refresh = nsecs_t(period);
+ }
- if (fbDev) {
- if (mRefreshPeriod == 0) {
- mRefreshPeriod = nsecs_t(1e9 / fbDev->fps);
- ALOGW("getting VSYNC period from fb HAL: %lld", mRefreshPeriod);
+ // these IDs are always reserved
+ for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
+ mAllocatedDisplayIDs.markBit(i);
+ // TODO: we query xdpi / ydpi / refresh
+ }
+
+ // the number of displays we actually have depends on the
+ // hw composer version
+ if (mHwc->common.version == HWC_DEVICE_API_VERSION_1_1) {
+ // 1.1 adds support for multiple displays
+ mNumDisplays = HWC_NUM_DISPLAY_TYPES;
+ } else if (mHwc->common.version > HWC_DEVICE_API_VERSION_1_1) {
+ // 1.2 adds support for virtual displays
+ mNumDisplays = MAX_DISPLAYS;
+ }
}
- mDpiX = fbDev->xdpi;
- mDpiY = fbDev->ydpi;
}
- if (mRefreshPeriod == 0) {
- mRefreshPeriod = nsecs_t(1e9 / 60.0);
- ALOGW("getting VSYNC period thin air: %lld", mRefreshPeriod);
+ if (fbDev) {
+ // if we're here it means we are on version 1.0
+ DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
+ disp.xdpi = fbDev->xdpi;
+ disp.ydpi = fbDev->ydpi;
+ if (disp.refresh == 0) {
+ disp.refresh = nsecs_t(1e9 / fbDev->fps);
+ ALOGW("getting VSYNC period from fb HAL: %lld", disp.refresh);
+ }
+ if (disp.refresh == 0) {
+ disp.refresh = nsecs_t(1e9 / 60.0);
+ ALOGW("getting VSYNC period thin air: %lld", mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
+ }
}
if (needVSyncThread) {
@@ -261,9 +157,7 @@ HWComposer::HWComposer(
}
HWComposer::~HWComposer() {
- hwcEventControl(mHwc, 0, EVENT_VSYNC, 0);
- for (size_t i = 0; i < MAX_DISPLAYS; i++)
- free(mLists[i]);
+ mHwc->eventControl(mHwc, 0, EVENT_VSYNC, 0);
if (mVSyncThread != NULL) {
mVSyncThread->requestExitAndWait();
}
@@ -277,12 +171,17 @@ status_t HWComposer::initCheck() const {
return mHwc ? NO_ERROR : NO_INIT;
}
-void HWComposer::hook_invalidate(struct hwc_procs* procs) {
- reinterpret_cast<cb_context *>(procs)->hwc->invalidate();
+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(struct hwc_procs* procs, int dpy, int64_t timestamp) {
- reinterpret_cast<cb_context *>(procs)->hwc->vsync(dpy, timestamp);
+void HWComposer::hook_vsync(const struct hwc_procs* procs, int dpy,
+ int64_t timestamp) {
+ cb_context* ctx = reinterpret_cast<cb_context*>(
+ const_cast<hwc_procs_t*>(procs));
+ ctx->hwc->vsync(dpy, timestamp);
}
void HWComposer::invalidate() {
@@ -296,8 +195,29 @@ void HWComposer::vsync(int dpy, int64_t timestamp) {
mLastHwVSync = timestamp;
}
+int32_t HWComposer::allocateDisplayId() {
+ if (mAllocatedDisplayIDs.count() >= mNumDisplays) {
+ return NO_MEMORY;
+ }
+ int32_t id = mAllocatedDisplayIDs.firstUnmarkedBit();
+ mAllocatedDisplayIDs.markBit(id);
+ return id;
+}
+
+status_t HWComposer::freeDisplayId(int32_t id) {
+ if (id < HWC_NUM_DISPLAY_TYPES) {
+ // cannot free the reserved IDs
+ return BAD_VALUE;
+ }
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+ return BAD_INDEX;
+ }
+ mAllocatedDisplayIDs.clearBit(id);
+ return NO_ERROR;
+}
+
nsecs_t HWComposer::getRefreshPeriod() const {
- return mRefreshPeriod;
+ return mDisplayData[HWC_DISPLAY_PRIMARY].refresh;
}
nsecs_t HWComposer::getRefreshTimestamp() const {
@@ -306,22 +226,22 @@ nsecs_t HWComposer::getRefreshTimestamp() const {
// the refresh period and whatever closest timestamp we have.
Mutex::Autolock _l(mLock);
nsecs_t now = systemTime(CLOCK_MONOTONIC);
- return now - ((now - mLastHwVSync) % mRefreshPeriod);
+ return now - ((now - mLastHwVSync) % mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
}
float HWComposer::getDpiX() const {
- return mDpiX;
+ return mDisplayData[HWC_DISPLAY_PRIMARY].xdpi;
}
float HWComposer::getDpiY() const {
- return mDpiY;
+ return mDisplayData[HWC_DISPLAY_PRIMARY].ydpi;
}
void HWComposer::eventControl(int event, int enabled) {
status_t err = NO_ERROR;
- if (mHwc && mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) {
+ if (mHwc) {
if (!mDebugForceFakeVSync) {
- err = hwcEventControl(mHwc, 0, event, enabled);
+ err = mHwc->eventControl(mHwc, 0, event, enabled);
// error here should not happen -- not sure what we should
// do if it does.
ALOGE_IF(err, "eventControl(%d, %d) failed %s",
@@ -335,140 +255,122 @@ void HWComposer::eventControl(int event, int enabled) {
}
status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
- // FIXME: handle multiple displays
- if (uint32_t(id) >= MAX_DISPLAYS)
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
return BAD_INDEX;
+ }
if (mHwc) {
- // TODO: must handle multiple displays here
- // mLists[0] is NULL only when this is called from the constructor
- if (!mLists[0] || mCapacity < numLayers) {
- free(mLists[0]);
- size_t size = sizeofHwcLayerList(mHwc, numLayers);
- mLists[0] = (hwc_display_contents_1_t*)malloc(size);
- mCapacity = numLayers;
- }
- hwcFlags(mHwc, mLists[0]) = HWC_GEOMETRY_CHANGED;
- hwcNumHwLayers(mHwc, mLists[0]) = numLayers;
- if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
- mLists[0]->flipFenceFd = -1;
+ DisplayData& disp(mDisplayData[id]);
+ if (disp.capacity < numLayers) {
+ const 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;
}
+ disp.list->flags = HWC_GEOMETRY_CHANGED;
+ disp.list->numHwLayers = numLayers;
+ disp.list->flipFenceFd = -1;
}
return NO_ERROR;
}
-status_t HWComposer::prepare() const {
- int err = hwcPrepare(mHwc, 1,
- const_cast<hwc_display_contents_1_t**>(mLists));
+status_t HWComposer::prepare() {
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ mLists[i] = mDisplayData[i].list;
+ if (mLists[i]) {
+ mLists[i]->dpy = EGL_NO_DISPLAY;
+ mLists[i]->sur = EGL_NO_SURFACE;
+ }
+ }
+ int err = mHwc->prepare(mHwc, mNumDisplays, mLists);
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.
- // It would be nice if we could get rid of this entirely, which I
- // think is almost possible.
-
- // TODO: must handle multiple displays here
-
- size_t numOVLayers = 0;
- size_t numFBLayers = 0;
- size_t count = getNumLayers(0);
-
- for (size_t i=0 ; i<count ; i++) {
- int compositionType;
- if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
- hwc_layer_1_t* l = &mLists[0]->hwLayers[i];
- if (l->flags & HWC_SKIP_LAYER) {
- l->compositionType = HWC_FRAMEBUFFER;
- }
- compositionType = l->compositionType;
- } else {
- // mList really has hwc_layer_list_t memory layout
- hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(mLists[0]);
- hwc_layer_t* l = &list0->hwLayers[i];
- if (l->flags & HWC_SKIP_LAYER) {
- l->compositionType = HWC_FRAMEBUFFER;
+ 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];
+ 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;
+ }
}
- compositionType = l->compositionType;
- }
-
- switch (compositionType) {
- case HWC_OVERLAY:
- numOVLayers++;
- break;
- case HWC_FRAMEBUFFER:
- numFBLayers++;
- break;
}
}
- mNumOVLayers = numOVLayers;
- mNumFBLayers = numFBLayers;
}
return (status_t)err;
}
-size_t HWComposer::getLayerCount(int32_t id, int type) const {
- // FIXME: handle multiple displays
- if (uint32_t(id) >= MAX_DISPLAYS) {
- // FIXME: in practice this is only use to know
- // if we have at least one layer of type.
- return (type == HWC_FRAMEBUFFER) ? 1 : 0;
- }
-
+bool HWComposer::hasHwcComposition(int32_t id) const {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ return false;
+ return mDisplayData[id].hasOvComp;
+}
- switch (type) {
- case HWC_OVERLAY:
- return mNumOVLayers;
- case HWC_FRAMEBUFFER:
- return mNumFBLayers;
- }
- return 0;
+bool HWComposer::hasGlesComposition(int32_t id) const {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+ return false;
+ return mDisplayData[id].hasFbComp;
}
-status_t HWComposer::commit(void* fbDisplay, void* fbSurface) const {
+status_t HWComposer::commit() {
int err = NO_ERROR;
if (mHwc) {
- err = hwcSet(mHwc, fbDisplay, fbSurface, 1,
- const_cast<hwc_display_contents_1_t**>(mLists));
- if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
- if (mLists[0]->flipFenceFd != -1) {
- close(mLists[0]->flipFenceFd);
- mLists[0]->flipFenceFd = -1;
+ if (mHwc->common.version == HWC_DEVICE_API_VERSION_1_0) {
+ // 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);
+ }
+
+ err = mHwc->set(mHwc, mNumDisplays, mLists);
+
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ DisplayData& disp(mDisplayData[i]);
+ if (disp.list) {
+ if (disp.list->flipFenceFd != -1) {
+ close(disp.list->flipFenceFd);
+ disp.list->flipFenceFd = -1;
+ }
+ disp.list->flags &= ~HWC_GEOMETRY_CHANGED;
}
}
- hwcFlags(mHwc, mLists[0]) &= ~HWC_GEOMETRY_CHANGED;
}
return (status_t)err;
}
status_t HWComposer::release() const {
if (mHwc) {
- if (hwcHasVsyncEvent(mHwc)) {
- hwcEventControl(mHwc, 0, HWC_EVENT_VSYNC, 0);
- }
- return (status_t)hwcBlank(mHwc, 0, 1);
+ mHwc->eventControl(mHwc, 0, HWC_EVENT_VSYNC, 0);
+ return (status_t)mHwc->blank(mHwc, 0, 1);
}
return NO_ERROR;
}
status_t HWComposer::acquire() const {
if (mHwc) {
- return (status_t)hwcBlank(mHwc, 0, 0);
+ return (status_t)mHwc->blank(mHwc, 0, 0);
}
return NO_ERROR;
}
-status_t HWComposer::disable() {
- if (mHwc) {
- hwcNumHwLayers(mHwc, mLists[0]) = 0;
- int err = hwcPrepare(mHwc, 1, mLists);
- return (status_t)err;
+size_t HWComposer::getNumLayers(int32_t id) const {
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+ return 0;
}
- return NO_ERROR;
-}
-
-size_t HWComposer::getNumLayers(int32_t id) const { // FIXME: handle multiple displays
- return mHwc ? hwcNumHwLayers(mHwc, mLists[0]) : 0;
+ return (mHwc && mDisplayData[id].list) ?
+ mDisplayData[id].list->numHwLayers : 0;
}
/*
@@ -496,78 +398,6 @@ private:
}
};
-// #if !HWC_REMOVE_DEPRECATED_VERSIONS
-/*
- * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_0_3
- * This implements the HWCLayer side of HWCIterableLayer.
- */
-class HWCLayerVersion0 : public Iterable<HWCLayerVersion0, hwc_layer_t> {
-public:
- HWCLayerVersion0(hwc_layer_t* layer)
- : Iterable<HWCLayerVersion0, hwc_layer_t>(layer) { }
-
- virtual int32_t getCompositionType() const {
- return getLayer()->compositionType;
- }
- virtual uint32_t getHints() const {
- return getLayer()->hints;
- }
- virtual int getAndResetReleaseFenceFd() {
- // not supported on VERSION_03
- return -1;
- }
- virtual void setAcquireFenceFd(int fenceFd) {
- if (fenceFd != -1) {
- ALOGE("HWC 0.x can't handle acquire fences");
- close(fenceFd);
- }
- }
-
- virtual void setDefaultState() {
- getLayer()->compositionType = HWC_FRAMEBUFFER;
- getLayer()->hints = 0;
- getLayer()->flags = HWC_SKIP_LAYER;
- getLayer()->transform = 0;
- getLayer()->blending = HWC_BLENDING_NONE;
- getLayer()->visibleRegionScreen.numRects = 0;
- getLayer()->visibleRegionScreen.rects = NULL;
- }
- virtual void setSkip(bool skip) {
- if (skip) {
- getLayer()->flags |= HWC_SKIP_LAYER;
- } else {
- getLayer()->flags &= ~HWC_SKIP_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) {
- reinterpret_cast<Rect&>(getLayer()->displayFrame) = frame;
- }
- virtual void setCrop(const Rect& crop) {
- reinterpret_cast<Rect&>(getLayer()->sourceCrop) = crop;
- }
- virtual void setVisibleRegionScreen(const Region& reg) {
- getLayer()->visibleRegionScreen.rects =
- reinterpret_cast<hwc_rect_t const *>(
- reg.getArray(&getLayer()->visibleRegionScreen.numRects));
- }
- 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 {
- getLayer()->handle = buffer->handle;
- }
- }
-};
-// #endif // !HWC_REMOVE_DEPRECATED_VERSIONS
-
/*
* Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0.
* This implements the HWCLayer side of HWCIterableLayer.
@@ -642,19 +472,14 @@ public:
* returns an iterator initialized at a given index in the layer list
*/
HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) {
- // FIXME: handle multiple displays
- if (uint32_t(id) >= MAX_DISPLAYS)
+ if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
return LayerListIterator();
-
- if (!mHwc || index > hwcNumHwLayers(mHwc, mLists[0]))
+ }
+ const DisplayData& disp(mDisplayData[id]);
+ if (!mHwc || !disp.list || index > disp.list->numHwLayers) {
return LayerListIterator();
- if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
- return LayerListIterator(new HWCLayerVersion1(mLists[0]->hwLayers),
- index);
- } else {
- hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(mLists[0]);
- return LayerListIterator(new HWCLayerVersion0(list0->hwLayers), index);
}
+ return LayerListIterator(new HWCLayerVersion1(disp.list->hwLayers), index);
}
/*
@@ -674,44 +499,41 @@ HWComposer::LayerListIterator HWComposer::end(int32_t id) {
void HWComposer::dump(String8& result, char* buffer, size_t SIZE,
const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const {
if (mHwc) {
- hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(mLists[0]);
-
result.append("Hardware Composer state:\n");
- result.appendFormat(" mDebugForceFakeVSync=%d\n",
- mDebugForceFakeVSync);
- result.appendFormat(" numHwLayers=%u, flags=%08x\n",
- hwcNumHwLayers(mHwc, mLists[0]), hwcFlags(mHwc, mLists[0]));
- result.append(
- " type | handle | hints | flags | tr | blend | format | source crop | frame name \n"
- "----------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n");
- // " ________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____]
- for (size_t i=0 ; i<hwcNumHwLayers(mHwc, mLists[0]) ; i++) {
- hwc_layer_1_t const* lp;
- if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
- lp = &mLists[0]->hwLayers[i];
- } else {
- // FIXME: here we rely on hwc_layer_1_t and hwc_layer_t having the same layout
- lp = reinterpret_cast<hwc_layer_1_t const*>(&list0->hwLayers[i]);
- }
- const sp<LayerBase> layer(visibleLayersSortedByZ[i]);
- int32_t format = -1;
- if (layer->getLayer() != NULL) {
- const sp<GraphicBuffer>& buffer(layer->getLayer()->getActiveBuffer());
- if (buffer != NULL) {
- format = buffer->getPixelFormat();
+ result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
+ for (size_t i=0 ; i<mNumDisplays ; i++) {
+ const DisplayData& disp(mDisplayData[i]);
+ if (disp.list) {
+ result.appendFormat(" id=%d, numHwLayers=%u, flags=%08x\n",
+ i, disp.list->numHwLayers, disp.list->flags);
+ result.append(
+ " type | handle | hints | flags | tr | blend | format | source crop | frame name \n"
+ "----------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n");
+ // " ________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____]
+ for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
+ const hwc_layer_1_t&l = disp.list->hwLayers[i];
+ const sp<LayerBase> layer(visibleLayersSortedByZ[i]);
+ int32_t format = -1;
+ if (layer->getLayer() != NULL) {
+ const sp<GraphicBuffer>& buffer(
+ layer->getLayer()->getActiveBuffer());
+ if (buffer != NULL) {
+ format = buffer->getPixelFormat();
+ }
+ }
+ result.appendFormat(
+ " %8s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n",
+ l.compositionType ? "OVERLAY" : "FB",
+ intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
+ l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
+ l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
+ layer->getName().string());
}
}
- const hwc_layer_1_t& l(*lp);
- result.appendFormat(
- " %8s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n",
- l.compositionType ? "OVERLAY" : "FB",
- intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
- l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
- l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
- layer->getName().string());
}
}
- if (mHwc && hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_0_1) && mHwc->dump) {
+
+ if (mHwc && mHwc->dump) {
mHwc->dump(mHwc, buffer, SIZE);
result.append(buffer);
}
@@ -722,7 +544,7 @@ void HWComposer::dump(String8& result, char* buffer, size_t SIZE,
HWComposer::VSyncThread::VSyncThread(HWComposer& hwc)
: mHwc(hwc), mEnabled(false),
mNextFakeVSync(0),
- mRefreshPeriod(hwc.mRefreshPeriod)
+ mRefreshPeriod(hwc.getRefreshPeriod())
{
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index ac2257e..7b92d2e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -28,6 +28,7 @@
#include <utils/Thread.h>
#include <utils/Timers.h>
#include <utils/Vector.h>
+#include <utils/BitSet.h>
extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *request,
@@ -58,9 +59,7 @@ public:
};
enum {
- MAIN = 0,
- HDMI = 1,
- MAX_DISPLAYS
+ MAX_DISPLAYS = HWC_NUM_DISPLAY_TYPES + 1
};
HWComposer(
@@ -72,14 +71,23 @@ public:
status_t initCheck() const;
- // Asks the HAL what it can do
- status_t prepare() const;
+ // returns a display ID starting at MAX_DISPLAYS, this ID
+ // is to be used with createWorkList (and all other
+ // methods requiring an ID below).
+ // IDs below MAX_DISPLAY are pre-defined and therefore are always valid.
+ // returns a negative error code if an ID cannot be allocated
+ int32_t allocateDisplayId();
+
+ // recycles the given ID and frees the associated worklist.
+ // IDs below MAX_DISPLAYS are not recycled
+ status_t freeDisplayId(int32_t id);
- // disable hwc until next createWorkList
- status_t disable();
+
+ // Asks the HAL what it can do
+ status_t prepare();
// commits the list
- status_t commit(void* fbDisplay, void* fbSurface) const;
+ status_t commit();
// release hardware resources and blank screen
status_t release() const;
@@ -90,9 +98,11 @@ public:
// create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
status_t createWorkList(int32_t id, size_t numLayers);
- // get number of layers of the given type as updated in prepare().
- // type is HWC_OVERLAY or HWC_FRAMEBUFFER
- size_t getLayerCount(int32_t id, int type) 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;
// needed forward declarations
class LayerListIterator;
@@ -231,32 +241,45 @@ private:
struct cb_context;
- static void hook_invalidate(struct hwc_procs* procs);
- static void hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp);
+ static void hook_invalidate(const struct hwc_procs* procs);
+ static void hook_vsync(const struct hwc_procs* procs, int dpy,
+ int64_t timestamp);
inline void invalidate();
inline void vsync(int dpy, int64_t timestamp);
+ struct DisplayData {
+ DisplayData() : xdpi(0), ydpi(0), refresh(0),
+ hasFbComp(false), hasOvComp(false),
+ capacity(0), list(NULL) { }
+ ~DisplayData() {
+ free(list);
+ }
+ float xdpi;
+ float ydpi;
+ nsecs_t refresh;
+ bool hasFbComp;
+ bool hasOvComp;
+ size_t capacity;
+ hwc_display_contents_1* list;
+ };
+
sp<SurfaceFlinger> mFlinger;
hw_module_t const* mModule;
struct hwc_composer_device_1* mHwc;
// invariant: mLists[0] != NULL iff mHwc != NULL
- // TODO: decide whether mLists[i>0] should be non-NULL when display i is
- // not attached/enabled.
+ // mLists[i>0] can be NULL. that display is to be ignored
struct hwc_display_contents_1* mLists[MAX_DISPLAYS];
+ DisplayData mDisplayData[MAX_DISPLAYS];
+ size_t mNumDisplays;
- size_t mCapacity;
- mutable size_t mNumOVLayers;
- mutable size_t mNumFBLayers;
cb_context* mCBContext;
EventHandler& mEventHandler;
- nsecs_t mRefreshPeriod;
- float mDpiX;
- float mDpiY;
size_t mVSyncCount;
sp<VSyncThread> mVSyncThread;
bool mDebugForceFakeVSync;
+ BitSet32 mAllocatedDisplayIDs;
// protected by mLock
mutable Mutex mLock;
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 3833f48..a39b7d8 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -19,6 +19,8 @@
#include <stdint.h>
#include <sys/types.h>
+#include <cutils/compiler.h>
+
#include <gui/BitTube.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/DisplayEventReceiver.h>
@@ -58,14 +60,6 @@ status_t EventThread::registerDisplayEventConnection(
return NO_ERROR;
}
-status_t EventThread::unregisterDisplayEventConnection(
- const wp<EventThread::Connection>& connection) {
- Mutex::Autolock _l(mLock);
- mDisplayEventConnections.remove(connection);
- mCondition.broadcast();
- return NO_ERROR;
-}
-
void EventThread::removeDisplayEventConnection(
const wp<EventThread::Connection>& connection) {
Mutex::Autolock _l(mLock);
@@ -120,118 +114,115 @@ void EventThread::onVSyncReceived(int, nsecs_t timestamp) {
}
bool EventThread::threadLoop() {
+ DisplayEventReceiver::Event vsync;
+ Vector< sp<EventThread::Connection> > signalConnections;
+ signalConnections = waitForEvent(&vsync);
+
+ // dispatch vsync events to listeners...
+ const size_t count = signalConnections.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<Connection>& conn(signalConnections[i]);
+ // now see if we still need to report this VSYNC event
+ status_t err = conn->postEvent(vsync);
+ if (err == -EAGAIN || err == -EWOULDBLOCK) {
+ // The destination doesn't accept events anymore, it's probably
+ // full. For now, we just drop the events on the floor.
+ // Note that some events cannot be dropped and would have to be
+ // re-sent later. Right-now we don't have the ability to do
+ // this, but it doesn't matter for VSYNC.
+ } else if (err < 0) {
+ // handle any other error on the pipe as fatal. the only
+ // reasonable thing to do is to clean-up this connection.
+ // The most common error we'll get here is -EPIPE.
+ removeDisplayEventConnection(signalConnections[i]);
+ }
+ }
+ return true;
+}
+
+Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
+ DisplayEventReceiver::Event* event)
+{
+ Mutex::Autolock _l(mLock);
- nsecs_t timestamp;
size_t vsyncCount;
- size_t activeEvents;
- DisplayEventReceiver::Event vsync;
- Vector< sp<EventThread::Connection> > activeConnections;
+ nsecs_t timestamp;
+ Vector< sp<EventThread::Connection> > signalConnections;
do {
- Mutex::Autolock _l(mLock);
// latch VSYNC event if any
+ bool waitForVSync = false;
+ vsyncCount = mVSyncCount;
timestamp = mVSyncTimestamp;
mVSyncTimestamp = 0;
- // check if we should be waiting for VSYNC events
- activeEvents = 0;
- bool waitForNextVsync = false;
+ // find out connections waiting for events
size_t count = mDisplayEventConnections.size();
for (size_t i=0 ; i<count ; i++) {
sp<Connection> connection(mDisplayEventConnections[i].promote());
if (connection != NULL) {
- activeConnections.add(connection);
if (connection->count >= 0) {
- // at least one continuous mode or active one-shot event
- waitForNextVsync = true;
- activeEvents++;
- break;
+ // we need vsync events because at least
+ // one connection is waiting for it
+ waitForVSync = true;
+ if (timestamp) {
+ // we consume the event only if it's time
+ // (ie: we received a vsync event)
+ if (connection->count == 0) {
+ // fired this time around
+ connection->count = -1;
+ signalConnections.add(connection);
+ } else if (connection->count == 1 ||
+ (vsyncCount % connection->count) == 0) {
+ // continuous event, and time to report it
+ signalConnections.add(connection);
+ }
+ }
}
+ } else {
+ // we couldn't promote this reference, the connection has
+ // died, so clean-up!
+ mDisplayEventConnections.removeAt(i);
+ --i; --count;
}
}
- if (timestamp) {
- if (!waitForNextVsync) {
- // we received a VSYNC but we have no clients
- // don't report it, and disable VSYNC events
- disableVSyncLocked();
- } else {
- // report VSYNC event
- break;
- }
- } else {
- // never disable VSYNC events immediately, instead
- // we'll wait to receive the event and we'll
- // reevaluate whether we need to dispatch it and/or
- // disable VSYNC events then.
- if (waitForNextVsync) {
- // enable
- enableVSyncLocked();
- }
+ // Here we figure out if we need to enable or disable vsyncs
+ if (timestamp && !waitForVSync) {
+ // we received a VSYNC but we have no clients
+ // don't report it, and disable VSYNC events
+ disableVSyncLocked();
+ } else if (!timestamp && waitForVSync) {
+ enableVSyncLocked();
}
- // wait for something to happen
- if (mUseSoftwareVSync && waitForNextVsync) {
- // h/w vsync cannot be used (screen is off), so we use
- // a timeout instead. it doesn't matter how imprecise this
- // is, we just need to make sure to serve the clients
- if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) {
- mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
- mVSyncCount++;
+ // note: !timestamp implies signalConnections.isEmpty()
+ if (!timestamp) {
+ // wait for something to happen
+ if (CC_UNLIKELY(mUseSoftwareVSync && waitForVSync)) {
+ // h/w vsync cannot be used (screen is off), so we use
+ // a timeout instead. it doesn't matter how imprecise this
+ // is, we just need to make sure to serve the clients
+ if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) {
+ mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+ mVSyncCount++;
+ }
+ } else {
+ // This is where we spend most of our time, waiting
+ // for a vsync events and registered clients
+ mCondition.wait(mLock);
}
- } else {
- mCondition.wait(mLock);
}
- vsyncCount = mVSyncCount;
- } while (!activeConnections.size());
+ } while (signalConnections.isEmpty());
- if (!activeEvents) {
- // no events to return. start over.
- // (here we make sure to exit the scope of this function
- // so that we release our Connection references)
- return true;
- }
+ // here we're guaranteed to have a timestamp and some connections to signal
// dispatch vsync events to listeners...
- vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
- vsync.header.timestamp = timestamp;
- vsync.vsync.count = vsyncCount;
+ event->header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+ event->header.timestamp = timestamp;
+ event->vsync.count = vsyncCount;
- const size_t count = activeConnections.size();
- for (size_t i=0 ; i<count ; i++) {
- const sp<Connection>& conn(activeConnections[i]);
- // now see if we still need to report this VSYNC event
- const int32_t vcount = conn->count;
- if (vcount >= 0) {
- bool reportVsync = false;
- if (vcount == 0) {
- // fired this time around
- conn->count = -1;
- reportVsync = true;
- } else if (vcount == 1 || (vsyncCount % vcount) == 0) {
- // continuous event, and time to report it
- reportVsync = true;
- }
-
- if (reportVsync) {
- status_t err = conn->postEvent(vsync);
- if (err == -EAGAIN || err == -EWOULDBLOCK) {
- // The destination doesn't accept events anymore, it's probably
- // full. For now, we just drop the events on the floor.
- // Note that some events cannot be dropped and would have to be
- // re-sent later. Right-now we don't have the ability to do
- // this, but it doesn't matter for VSYNC.
- } else if (err < 0) {
- // handle any other error on the pipe as fatal. the only
- // reasonable thing to do is to clean-up this connection.
- // The most common error we'll get here is -EPIPE.
- removeDisplayEventConnection(activeConnections[i]);
- }
- }
- }
- }
-
- return true;
+ return signalConnections;
}
void EventThread::enableVSyncLocked() {
@@ -279,7 +270,8 @@ EventThread::Connection::Connection(
}
EventThread::Connection::~Connection() {
- mEventThread->unregisterDisplayEventConnection(this);
+ // do nothing here -- clean-up will happen automatically
+ // when the main thread wakes up
}
void EventThread::Connection::onFirstRef() {
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index d23b9fa..20ea34d 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -47,7 +47,6 @@ class EventThread : public Thread {
// count >= 1 : continuous event. count is the vsync rate
// count == 0 : one-shot event that has not fired
// count ==-1 : one-shot event that fired this round / disabled
- // count ==-2 : one-shot event that fired the round before
int32_t count;
private:
@@ -66,7 +65,6 @@ public:
sp<Connection> createEventConnection() const;
status_t registerDisplayEventConnection(const sp<Connection>& connection);
- status_t unregisterDisplayEventConnection(const wp<Connection>& connection);
void setVsyncRate(uint32_t count, const sp<Connection>& connection);
void requestNextVsync(const sp<Connection>& connection);
@@ -80,6 +78,9 @@ public:
// called when receiving a vsync event
void onVSyncReceived(int display, nsecs_t timestamp);
+ Vector< sp<EventThread::Connection> > waitForEvent(
+ DisplayEventReceiver::Event* event);
+
void dump(String8& result, char* buffer, size_t SIZE) const;
private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c63d0cf..e6e258f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -409,7 +409,8 @@ status_t SurfaceFlinger::readyToRun()
mCurrentState.displays.add(mDefaultDisplays[i], DisplayDeviceState(i));
}
sp<DisplayDevice> hw = new DisplayDevice(this,
- DisplayDevice::DISPLAY_ID_MAIN, anw, fbs, mEGLConfig);
+ DisplayDevice::DISPLAY_ID_MAIN, HWC_DISPLAY_PRIMARY,
+ anw, fbs, mEGLConfig);
mDisplays.add(hw->getDisplayId(), hw);
// initialize OpenGL ES
@@ -779,29 +780,30 @@ void SurfaceFlinger::setUpHWComposer() {
mHwWorkListDirty = false;
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
- const Vector< sp<LayerBase> >& currentLayers(
+ const int32_t id = hw->getHwcDisplayId();
+ if (id >= 0) {
+ const Vector< sp<LayerBase> >& currentLayers(
hw->getVisibleLayersSortedByZ());
- const size_t count = currentLayers.size();
-
- const int32_t id = hw->getDisplayId();
- if (hwc.createWorkList(id, count) >= 0) {
- 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<LayerBase>& layer(currentLayers[i]);
-
- if (CC_UNLIKELY(workListsDirty)) {
- layer->setGeometry(hw, *cur);
- if (mDebugDisableHWC || mDebugRegion) {
- cur->setSkip(true);
+ const size_t count = currentLayers.size();
+ if (hwc.createWorkList(id, count) >= 0) {
+ 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<LayerBase>& layer(currentLayers[i]);
+
+ if (CC_UNLIKELY(workListsDirty)) {
+ layer->setGeometry(hw, *cur);
+ if (mDebugDisableHWC || mDebugRegion) {
+ cur->setSkip(true);
+ }
}
- }
- /*
- * update the per-frame h/w composer data for each layer
- * and build the transparent region of the FB
- */
- layer->setPerFrameData(hw, *cur);
+ /*
+ * update the per-frame h/w composer data for each layer
+ * and build the transparent region of the FB
+ */
+ layer->setPerFrameData(hw, *cur);
+ }
}
}
}
@@ -841,21 +843,20 @@ void SurfaceFlinger::postFramebuffer()
HWComposer& hwc(getHwComposer());
if (hwc.initCheck() == NO_ERROR) {
- // FIXME: eventually commit() won't take arguments
// FIXME: EGL spec says:
// "surface must be bound to the calling thread's current context,
// for the current rendering API."
DisplayDevice::makeCurrent(
getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN), mEGLContext);
- hwc.commit(mEGLDisplay, getDefaultDisplayDevice()->getEGLSurface());
+ hwc.commit();
}
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ());
const size_t count = currentLayers.size();
- if (hwc.initCheck() == NO_ERROR) {
- int32_t id = hw->getDisplayId();
+ 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) {
@@ -951,12 +952,15 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
if (state.surface->asBinder() != draw[i].surface->asBinder()) {
// changing the surface is like destroying and
// recreating the DisplayDevice
+ const int32_t hwcDisplayId =
+ (uint32_t(state.id) < DisplayDevice::DISPLAY_ID_COUNT) ?
+ state.id : getHwComposer().allocateDisplayId();
sp<SurfaceTextureClient> stc(
new SurfaceTextureClient(state.surface));
sp<DisplayDevice> disp = new DisplayDevice(this,
- state.id, stc, 0, mEGLConfig);
+ state.id, hwcDisplayId, stc, 0, mEGLConfig);
disp->setLayerStack(state.layerStack);
disp->setOrientation(state.orientation);
@@ -982,10 +986,14 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
for (size_t i=0 ; i<cc ; i++) {
if (draw.indexOfKey(curr.keyAt(i)) < 0) {
const DisplayDeviceState& state(curr[i]);
+ const int32_t hwcDisplayId =
+ (uint32_t(state.id) < DisplayDevice::DISPLAY_ID_COUNT) ?
+ state.id : getHwComposer().allocateDisplayId();
+
sp<SurfaceTextureClient> stc(
new SurfaceTextureClient(state.surface));
- sp<DisplayDevice> disp = new DisplayDevice(this, state.id,
- stc, 0, mEGLConfig);
+ sp<DisplayDevice> disp = new DisplayDevice(this,
+ state.id, hwcDisplayId, stc, 0, mEGLConfig);
mDisplays.add(state.id, disp);
}
}
@@ -1251,12 +1259,13 @@ void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
{
HWComposer& hwc(getHwComposer());
- int32_t id = hw->getDisplayId();
+ int32_t id = hw->getHwcDisplayId();
HWComposer::LayerListIterator cur = hwc.begin(id);
const HWComposer::LayerListIterator end = hwc.end(id);
- const size_t fbLayerCount = hwc.getLayerCount(id, HWC_FRAMEBUFFER);
- if (cur==end || fbLayerCount) {
+ const bool hasGlesComposition = hwc.hasGlesComposition(id);
+ const bool hasHwcComposition = hwc.hasHwcComposition(id);
+ if (cur==end || hasGlesComposition) {
DisplayDevice::makeCurrent(hw, mEGLContext);
@@ -1265,7 +1274,7 @@ void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const
glLoadIdentity();
// Never touch the framebuffer if we don't have any framebuffer layers
- if (hwc.getLayerCount(id, HWC_OVERLAY)) {
+ 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