diff options
-rw-r--r-- | include/gui/BufferItemConsumer.h | 91 | ||||
-rw-r--r-- | include/gui/CpuConsumer.h | 4 | ||||
-rw-r--r-- | include/ui/Fence.h | 3 | ||||
-rw-r--r-- | include/utils/VectorImpl.h | 20 | ||||
-rw-r--r-- | libs/gui/Android.mk | 3 | ||||
-rw-r--r-- | libs/gui/BufferItemConsumer.cpp | 93 | ||||
-rw-r--r-- | libs/gui/CpuConsumer.cpp | 3 | ||||
-rw-r--r-- | libs/utils/VectorImpl.cpp | 19 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayDevice.cpp | 4 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayDevice.h | 12 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayHardware/HWComposer.cpp | 558 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayHardware/HWComposer.h | 65 | ||||
-rw-r--r-- | services/surfaceflinger/EventThread.cpp | 184 | ||||
-rw-r--r-- | services/surfaceflinger/EventThread.h | 5 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 73 |
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 |