From 3e8b853d67c737abdb363f9c978e7d83eac4d888 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Sun, 13 May 2012 20:42:01 -0700 Subject: [PATCH] refactor HWComposer to break dependency with the HAL headers HWComposer must abstract the HWC HAL entirely, so that the HAL can continue to evolve (and break binary compatibility) without breaking SurfaceFlinger. The HWC data structure had leaked outside of HWComposer, this is now fixed. We now have an abstract interface that provide all the needed functionality, HWCompose provides concrete implementations of it based on the the HWC version. Change-Id: I40c4676dc986b682ede5520a1c60efe64037b0bb --- .../DisplayHardware/HWComposer.cpp | 136 +++++++++++++++++- .../DisplayHardware/HWComposer.h | 131 ++++++++++++++--- services/surfaceflinger/Layer.cpp | 34 ++--- services/surfaceflinger/Layer.h | 4 +- services/surfaceflinger/LayerBase.cpp | 38 ++--- services/surfaceflinger/LayerBase.h | 6 +- services/surfaceflinger/SurfaceFlinger.cpp | 33 +++-- 7 files changed, 284 insertions(+), 98 deletions(-) diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 65763db8d..ce63ee719 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -43,6 +43,19 @@ namespace android { // --------------------------------------------------------------------------- +struct HWComposer::cb_context { + struct callbacks : public hwc_procs_t { + // these are here to facilitate the transition when adding + // new callbacks (an implementation can check for NULL before + // calling a new callback). + void (*zero[4])(void); + }; + callbacks procs; + HWComposer* hwc; +}; + +// --------------------------------------------------------------------------- + HWComposer::HWComposer( const sp& flinger, EventHandler& handler, @@ -51,6 +64,7 @@ HWComposer::HWComposer( mModule(0), mHwc(0), mList(0), mCapacity(0), mNumOVLayers(0), mNumFBLayers(0), mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE), + mCBContext(new cb_context), mEventHandler(handler), mRefreshPeriod(refreshPeriod), mVSyncCount(0), mDebugForceFakeVSync(false) @@ -68,11 +82,11 @@ HWComposer::HWComposer( HWC_HARDWARE_COMPOSER, strerror(-err)); if (err == 0) { 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)); + 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)); } if (mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) { if (mDebugForceFakeVSync) { @@ -102,6 +116,7 @@ HWComposer::~HWComposer() { if (mHwc) { hwc_close(mHwc); } + delete mCBContext; } status_t HWComposer::initCheck() const { @@ -230,10 +245,117 @@ size_t HWComposer::getNumLayers() const { return mList ? mList->numHwLayers : 0; } -hwc_layer_t* HWComposer::getLayers() const { - return mList ? mList->hwLayers : 0; +/* + * Helper template to implement a concrete HWCLayer + * This holds the pointer to the concrete hwc layer type + * and implements the "iterable" side of HWCLayer. + */ +template +class Iterable : public HWComposer::HWCLayer { +protected: + HWCTYPE* const mLayerList; + HWCTYPE* mCurrentLayer; + Iterable(HWCTYPE* layer) : mLayerList(layer), mCurrentLayer(layer) { } + inline HWCTYPE const * getLayer() const { return mCurrentLayer; } + inline HWCTYPE* getLayer() { return mCurrentLayer; } + virtual ~Iterable() { } +private: + // returns a copy of ourselves + virtual HWComposer::HWCLayer* dup() { + return new CONCRETE( static_cast(*this) ); + } + virtual status_t setLayer(size_t index) { + mCurrentLayer = &mLayerList[index]; + return NO_ERROR; + } +}; + +/* + * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_0_3 + * This implements the HWCLayer side of HWCIterableLayer. + */ +class HWCLayerVersion03 : public Iterable { +public: + HWCLayerVersion03(hwc_layer_t* layer) + : Iterable(layer) { } + + virtual int32_t getCompositionType() const { + return getLayer()->compositionType; + } + virtual uint32_t getHints() const { + return getLayer()->hints; + } + + 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(getLayer()->displayFrame) = frame; + } + virtual void setCrop(const Rect& crop) { + reinterpret_cast(getLayer()->sourceCrop) = crop; + } + virtual void setVisibleRegionScreen(const Region& reg) { + getLayer()->visibleRegionScreen.rects = + reinterpret_cast( + reg.getArray(&getLayer()->visibleRegionScreen.numRects)); + } + virtual void setBuffer(const sp& buffer) { + if (buffer == 0 || buffer->handle == 0) { + getLayer()->compositionType = HWC_FRAMEBUFFER; + getLayer()->flags |= HWC_SKIP_LAYER; + getLayer()->handle = 0; + } else { + getLayer()->handle = buffer->handle; + } + } +}; + +/* + * returns an iterator initialized at a given index in the layer list + */ +HWComposer::LayerListIterator HWComposer::getLayerIterator(size_t index) { + if (!mList || index > mList->numHwLayers) { + return LayerListIterator(); + } + return LayerListIterator(new HWCLayerVersion03(mList->hwLayers), index); } +/* + * returns an iterator on the beginning of the layer list + */ +HWComposer::LayerListIterator HWComposer::begin() { + return getLayerIterator(0); +} + +/* + * returns an iterator on the end of the layer list + */ +HWComposer::LayerListIterator HWComposer::end() { + return getLayerIterator(getNumLayers()); +} + + + void HWComposer::dump(String8& result, char* buffer, size_t SIZE, const Vector< sp >& visibleLayersSortedByZ) const { if (mHwc && mList) { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index aada3cd06..cafa24712 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -22,7 +22,7 @@ #include -#include +#include #include #include @@ -31,12 +31,17 @@ extern "C" int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *request, struct timespec *remain); +struct hwc_composer_device; +struct hwc_layer_list; +struct hwc_procs; + namespace android { // --------------------------------------------------------------------------- class String8; class SurfaceFlinger; class LayerBase; +class GraphicBuffer; class HWComposer { @@ -57,9 +62,6 @@ public: // tells the HAL what the framebuffer is void setFrameBuffer(EGLDisplay dpy, EGLSurface sur); - // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED. - status_t createWorkList(size_t numLayers); - // Asks the HAL what it can do status_t prepare() const; @@ -72,14 +74,109 @@ public: // release hardware resources status_t release() const; + // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED. + status_t createWorkList(size_t numLayers); + // get the layer array created by createWorkList() size_t getNumLayers() const; - hwc_layer_t* getLayers() const; // get number of layers of the given type as updated in prepare(). // type is HWC_OVERLAY or HWC_FRAMEBUFFER size_t getLayerCount(int type) const; + // needed forward declarations + class LayerListIterator; + + /* + * Interface to hardware composer's layers functionality. + * This abstracts the HAL interface to layers which can evolve in + * incompatible ways from one release to another. + * The idea is that we could extend this interface as we add + * features to h/w composer. + */ + class HWCLayerInterface { + protected: + virtual ~HWCLayerInterface() { } + public: + virtual int32_t getCompositionType() const = 0; + virtual uint32_t getHints() const = 0; + virtual void setDefaultState() = 0; + virtual void setSkip(bool skip) = 0; + virtual void setBlending(uint32_t blending) = 0; + virtual void setTransform(uint32_t transform) = 0; + virtual void setFrame(const Rect& frame) = 0; + virtual void setCrop(const Rect& crop) = 0; + virtual void setVisibleRegionScreen(const Region& reg) = 0; + virtual void setBuffer(const sp& buffer) = 0; + }; + + /* + * Interface used to implement an iterator to a list + * of HWCLayer. + */ + class HWCLayer : public HWCLayerInterface { + friend class LayerListIterator; + // select the layer at the given index + virtual status_t setLayer(size_t index) = 0; + virtual HWCLayer* dup() = 0; + static HWCLayer* copy(HWCLayer *rhs) { + return rhs ? rhs->dup() : NULL; + } + protected: + virtual ~HWCLayer() { } + }; + + /* + * Iterator through a HWCLayer list. + * This behaves more or less like a forward iterator. + */ + class LayerListIterator { + friend struct HWComposer; + HWCLayer* const mLayerList; + size_t mIndex; + + LayerListIterator() : mLayerList(NULL), mIndex(0) { } + + LayerListIterator(HWCLayer* layer, size_t index) + : mLayerList(layer), mIndex(index) { } + + // we don't allow assignment, because we don't need it for now + LayerListIterator& operator = (const LayerListIterator& rhs); + + public: + // copy operators + LayerListIterator(const LayerListIterator& rhs) + : mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) { + } + + ~LayerListIterator() { delete mLayerList; } + + // pre-increment + LayerListIterator& operator++() { + mLayerList->setLayer(++mIndex); + return *this; + } + + // dereference + HWCLayerInterface& operator * () { return *mLayerList; } + HWCLayerInterface* operator -> () { return mLayerList; } + + // comparison + bool operator == (const LayerListIterator& rhs) const { + return mIndex == rhs.mIndex; + } + bool operator != (const LayerListIterator& rhs) const { + return !operator==(rhs); + } + }; + + // Returns an iterator to the beginning of the layer list + LayerListIterator begin(); + + // Returns an iterator to the end of the layer list + LayerListIterator end(); + + // Events handling --------------------------------------------------------- enum { @@ -111,18 +208,9 @@ public: const Vector< sp >& visibleLayersSortedByZ) const; private: + LayerListIterator getLayerIterator(size_t index); - struct callbacks : public hwc_procs_t { - // these are here to facilitate the transition when adding - // new callbacks (an implementation can check for NULL before - // calling a new callback). - void (*zero[4])(void); - }; - - struct cb_context { - callbacks procs; - HWComposer* hwc; - }; + struct cb_context; static void hook_invalidate(struct hwc_procs* procs); static void hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp); @@ -132,14 +220,14 @@ private: sp mFlinger; hw_module_t const* mModule; - hwc_composer_device_t* mHwc; - hwc_layer_list_t* mList; + struct hwc_composer_device* mHwc; + struct hwc_layer_list* mList; size_t mCapacity; mutable size_t mNumOVLayers; mutable size_t mNumFBLayers; - hwc_display_t mDpy; - hwc_surface_t mSur; - cb_context mCBContext; + EGLDisplay mDpy; + EGLSurface mSur; + cb_context* mCBContext; EventHandler& mEventHandler; nsecs_t mRefreshPeriod; size_t mVSyncCount; @@ -147,7 +235,6 @@ private: bool mDebugForceFakeVSync; }; - // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 40623404d..890bcb446 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -259,16 +259,17 @@ Rect Layer::computeBufferCrop() const { return crop; } -void Layer::setGeometry(hwc_layer_t* hwcl) +void Layer::setGeometry(HWComposer::HWCLayerInterface& layer) { - LayerBaseClient::setGeometry(hwcl); + LayerBaseClient::setGeometry(layer); - hwcl->flags &= ~HWC_SKIP_LAYER; + // enable this layer + layer.setSkip(false); // we can't do alpha-fade with the hwc HAL const State& s(drawingState()); if (s.alpha < 0xFF) { - hwcl->flags = HWC_SKIP_LAYER; + layer.setSkip(true); } /* @@ -288,29 +289,18 @@ void Layer::setGeometry(hwc_layer_t* hwcl) // we can only handle simple transformation if (finalTransform & Transform::ROT_INVALID) { - hwcl->flags = HWC_SKIP_LAYER; + layer.setSkip(true); } else { - hwcl->transform = finalTransform; + layer.setTransform(finalTransform); } - - Rect crop = computeBufferCrop(); - hwcl->sourceCrop.left = crop.left; - hwcl->sourceCrop.top = crop.top; - hwcl->sourceCrop.right = crop.right; - hwcl->sourceCrop.bottom = crop.bottom; + layer.setCrop(computeBufferCrop()); } -void Layer::setPerFrameData(hwc_layer_t* hwcl) { +void Layer::setPerFrameData(HWComposer::HWCLayerInterface& layer) { const sp& buffer(mActiveBuffer); - if (buffer == NULL) { - // this can happen if the client never drew into this layer yet, - // or if we ran out of memory. In that case, don't let - // HWC handle it. - hwcl->flags |= HWC_SKIP_LAYER; - hwcl->handle = NULL; - } else { - hwcl->handle = buffer->handle; - } + // NOTE: buffer can be NULL if the client never drew into this + // layer yet, or if we ran out of memory + layer.setBuffer(buffer); } void Layer::onDraw(const Region& clip) const diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 393599f3a..7a164aa4e 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -64,8 +64,8 @@ public: bool isFixedSize() const; // LayerBase interface - virtual void setGeometry(hwc_layer_t* hwcl); - virtual void setPerFrameData(hwc_layer_t* hwcl); + virtual void setGeometry(HWComposer::HWCLayerInterface& layer); + virtual void setPerFrameData(HWComposer::HWCLayerInterface& layer); virtual void onDraw(const Region& clip) const; virtual uint32_t doTransaction(uint32_t transactionFlags); virtual void lockPageFlip(bool& recomputeVisibleRegions); diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index 16bac8f79..fe15dc90a 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -281,48 +281,34 @@ void LayerBase::unlockPageFlip( const Transform& planeTransform, Region& outDirtyRegion) { } -void LayerBase::setGeometry(hwc_layer_t* hwcl) +void LayerBase::setGeometry(HWComposer::HWCLayerInterface& layer) { - hwcl->compositionType = HWC_FRAMEBUFFER; - hwcl->hints = 0; - hwcl->flags = HWC_SKIP_LAYER; - hwcl->transform = 0; - hwcl->blending = HWC_BLENDING_NONE; + layer.setDefaultState(); // this gives us only the "orientation" component of the transform const State& s(drawingState()); const uint32_t finalTransform = s.transform.getOrientation(); // we can only handle simple transformation if (finalTransform & Transform::ROT_INVALID) { - hwcl->flags = HWC_SKIP_LAYER; + layer.setTransform(0); } else { - hwcl->transform = finalTransform; + layer.setTransform(finalTransform); } if (!isOpaque()) { - hwcl->blending = mPremultipliedAlpha ? - HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE; + layer.setBlending(mPremultipliedAlpha ? + HWC_BLENDING_PREMULT : + HWC_BLENDING_COVERAGE); } // scaling is already applied in mTransformedBounds - hwcl->displayFrame.left = mTransformedBounds.left; - hwcl->displayFrame.top = mTransformedBounds.top; - hwcl->displayFrame.right = mTransformedBounds.right; - hwcl->displayFrame.bottom = mTransformedBounds.bottom; - hwcl->visibleRegionScreen.rects = - reinterpret_cast( - visibleRegionScreen.getArray( - &hwcl->visibleRegionScreen.numRects)); - - hwcl->sourceCrop.left = 0; - hwcl->sourceCrop.top = 0; - hwcl->sourceCrop.right = mTransformedBounds.width(); - hwcl->sourceCrop.bottom = mTransformedBounds.height(); + layer.setFrame(mTransformedBounds); + layer.setVisibleRegionScreen(visibleRegionScreen); + layer.setCrop(mTransformedBounds.getBounds()); } -void LayerBase::setPerFrameData(hwc_layer_t* hwcl) { - hwcl->compositionType = HWC_FRAMEBUFFER; - hwcl->handle = NULL; +void LayerBase::setPerFrameData(HWComposer::HWCLayerInterface& layer) { + layer.setBuffer(0); } void LayerBase::setFiltering(bool filtering) diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index c547a4072..4d5d1e402 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -32,8 +32,6 @@ #include -#include - #include "DisplayHardware/DisplayHardware.h" #include "Transform.h" @@ -116,8 +114,8 @@ public: virtual const char* getTypeId() const { return "LayerBase"; } - virtual void setGeometry(hwc_layer_t* hwcl); - virtual void setPerFrameData(hwc_layer_t* hwcl); + virtual void setGeometry(HWComposer::HWCLayerInterface& layer); + virtual void setPerFrameData(HWComposer::HWCLayerInterface& layer); /** diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 61b5f71e0..e2c7aeda1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -800,12 +800,13 @@ void SurfaceFlinger::handleWorkList() const Vector< sp >& currentLayers(mVisibleLayersSortedByZ); const size_t count = currentLayers.size(); hwc.createWorkList(count); - hwc_layer_t* const cur(hwc.getLayers()); - for (size_t i=0 ; cur && isetGeometry(&cur[i]); + + HWComposer::LayerListIterator cur = hwc.begin(); + const HWComposer::LayerListIterator end = hwc.end(); + for (size_t i=0 ; cur!=end && isetGeometry(*cur); if (mDebugDisableHWC || mDebugRegion) { - cur[i].compositionType = HWC_FRAMEBUFFER; - cur[i].flags |= HWC_SKIP_LAYER; + cur->setSkip(true); } } } @@ -859,8 +860,10 @@ void SurfaceFlinger::setupHardwareComposer() { const DisplayHardware& hw(graphicPlane(0).displayHardware()); HWComposer& hwc(hw.getHwComposer()); - hwc_layer_t* const cur(hwc.getLayers()); - if (!cur) { + + HWComposer::LayerListIterator cur = hwc.begin(); + const HWComposer::LayerListIterator end = hwc.end(); + if (cur == end) { return; } @@ -880,9 +883,9 @@ void SurfaceFlinger::setupHardwareComposer() * update the per-frame h/w composer data for each layer * and build the transparent region of the FB */ - for (size_t i=0 ; i& layer(layers[i]); - layer->setPerFrameData(&cur[i]); + layer->setPerFrameData(*cur); } status_t err = hwc.prepare(); ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); @@ -892,10 +895,11 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty) { const DisplayHardware& hw(graphicPlane(0).displayHardware()); HWComposer& hwc(hw.getHwComposer()); - hwc_layer_t* const cur(hwc.getLayers()); + HWComposer::LayerListIterator cur = hwc.begin(); + const HWComposer::LayerListIterator end = hwc.end(); const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER); - if (!cur || fbLayerCount) { + if (cur==end || fbLayerCount) { // Never touch the framebuffer if we don't have any framebuffer layers if (hwc.getLayerCount(HWC_OVERLAY)) { @@ -920,13 +924,12 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty) const Vector< sp >& layers(mVisibleLayersSortedByZ); const size_t count = layers.size(); - - for (size_t i=0 ; i& layer(layers[i]); const Region clip(dirty.intersect(layer->visibleRegionScreen)); if (!clip.isEmpty()) { - if (cur && (cur[i].compositionType == HWC_OVERLAY)) { - if (i && (cur[i].hints & HWC_HINT_CLEAR_FB) + if (cur->getCompositionType() == HWC_OVERLAY) { + if (i && (cur->getHints() & HWC_HINT_CLEAR_FB) && layer->isOpaque()) { // never clear the very first layer since we're // guaranteed the FB is already cleared