diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index a14bfb569..79772edec 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -5,6 +5,7 @@ LOCAL_SRC_FILES:= \ clz.cpp.arm \ DisplayHardware/DisplayHardware.cpp \ DisplayHardware/DisplayHardwareBase.cpp \ + DisplayHardware/HWComposer.cpp \ BlurFilter.cpp.arm \ GLExtensions.cpp \ Layer.cpp \ diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp index 2eac0a80a..166c52804 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -36,11 +36,11 @@ #include "DisplayHardware/DisplayHardware.h" -#include #include #include #include "GLExtensions.h" +#include "HWComposer.h" using namespace android; @@ -76,7 +76,7 @@ DisplayHardware::DisplayHardware( const sp& flinger, uint32_t dpy) : DisplayHardwareBase(flinger, dpy), - mFlags(0) + mFlags(0), mHwc(0) { init(dpy); } @@ -262,6 +262,17 @@ void DisplayHardware::init(uint32_t dpy) // Unbind the context from this thread eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + + // initialize the H/W composer + mHwc = new HWComposer(); + if (mHwc->initCheck() == NO_ERROR) { + mHwc->setFrameBuffer(mDisplay, mSurface); + } +} + +HWComposer& DisplayHardware::getHwComposer() const { + return *mHwc; } /* @@ -317,7 +328,12 @@ void DisplayHardware::flip(const Region& dirty) const } mPageFlipCount++; - eglSwapBuffers(dpy, surface); + + if (mHwc->initCheck() == NO_ERROR) { + mHwc->commit(); + } else { + eglSwapBuffers(dpy, surface); + } checkEGLErrors("eglSwapBuffers"); // for debugging diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h index 66bf5215d..f2cfd2db5 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h @@ -34,12 +34,11 @@ #include "DisplayHardware/DisplayHardwareBase.h" struct overlay_control_device_t; -struct framebuffer_device_t; -struct copybit_image_t; namespace android { class FramebufferNativeWindow; +class HWComposer; class DisplayHardware : public DisplayHardwareBase { @@ -80,6 +79,9 @@ public: uint32_t getPageFlipCount() const; EGLDisplay getEGLDisplay() const { return mDisplay; } overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; } + + // Hardware Composer + HWComposer& getHwComposer() const; status_t compositionComplete() const; @@ -107,6 +109,8 @@ private: GLint mMaxViewportDims; GLint mMaxTextureSize; + HWComposer* mHwc; + sp mNativeWindow; overlay_control_device_t* mOverlayEngine; }; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp new file mode 100644 index 000000000..518c5fe26 --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#include + +#include + +#include + +#include "HWComposer.h" + +namespace android { +// --------------------------------------------------------------------------- + +HWComposer::HWComposer() + : mModule(0), mHwc(0), mList(0), + mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE) +{ + int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule); + LOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID); + if (err == 0) { + err = hwc_open(mModule, &mHwc); + LOGE_IF(err, "%s device failed to initialize (%s)", + HWC_HARDWARE_COMPOSER, strerror(-err)); + } +} + +HWComposer::~HWComposer() { + free(mList); + if (mHwc) { + hwc_close(mHwc); + } +} + +status_t HWComposer::initCheck() const { + return mHwc ? NO_ERROR : NO_INIT; +} + +void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) { + mDpy = (hwc_display_t)dpy; + mSur = (hwc_surface_t)sur; +} + +status_t HWComposer::createWorkList(size_t numLayers) { + if (mHwc && (!mList || mList->numHwLayers < numLayers)) { + free(mList); + size_t size = sizeof(hwc_layer_list) + numLayers*sizeof(hwc_layer_t); + mList = (hwc_layer_list_t*)malloc(size); + mList->flags = HWC_GEOMETRY_CHANGED; + mList->numHwLayers = numLayers; + } + return NO_ERROR; +} + +status_t HWComposer::prepare() const { + int err = mHwc->prepare(mHwc, mList); + return (status_t)err; +} + +status_t HWComposer::commit() const { + int err = mHwc->set(mHwc, mDpy, mSur, mList); + mList->flags &= ~HWC_GEOMETRY_CHANGED; + return (status_t)err; +} + +HWComposer::iterator HWComposer::begin() { + return mList ? &(mList->hwLayers[0]) : NULL; +} + +HWComposer::iterator HWComposer::end() { + return mList ? &(mList->hwLayers[mList->numHwLayers]) : NULL; +} + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h new file mode 100644 index 000000000..729f23bbe --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SF_HWCOMPOSER_H +#define ANDROID_SF_HWCOMPOSER_H + +#include +#include + +#include + +#include + +namespace android { +// --------------------------------------------------------------------------- + +class HWComposer +{ +public: + + HWComposer(); + ~HWComposer(); + + status_t initCheck() const; + + // tells the HAL what the framebuffer is + void setFrameBuffer(EGLDisplay dpy, EGLSurface sur); + + // create a work list for numLayers layer + status_t createWorkList(size_t numLayers); + + // Asks the HAL what it can do + status_t prepare() const; + + // commits the list + status_t commit() const; + + + typedef hwc_layer_t const * const_iterator; + typedef hwc_layer_t* iterator; + + iterator begin(); + iterator end(); + +private: + hw_module_t const* mModule; + hwc_composer_device_t* mHwc; + hwc_layer_list_t* mList; + hwc_display_t mDpy; + hwc_surface_t mSur; +}; + + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SF_HWCOMPOSER_H diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 629d993ca..3720e1669 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -35,6 +35,7 @@ #include "Layer.h" #include "SurfaceFlinger.h" #include "DisplayHardware/DisplayHardware.h" +#include "DisplayHardware/HWComposer.h" #define DEBUG_RESIZE 0 @@ -177,6 +178,62 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, return NO_ERROR; } +void Layer::setGeometry(hwc_layer_t* hwcl) +{ + hwcl->compositionType = HWC_FRAMEBUFFER; + hwcl->hints = 0; + hwcl->flags = 0; + hwcl->transform = 0; + hwcl->blending = HWC_BLENDING_NONE; + + // we can't do alpha-fade with the hwc HAL + const State& s(drawingState()); + if (s.alpha < 0xFF) { + hwcl->flags = HWC_SKIP_LAYER; + return; + } + + // we can only handle simple transformation + if (mOrientation & Transform::ROT_INVALID) { + hwcl->flags = HWC_SKIP_LAYER; + return; + } + + hwcl->transform = mOrientation; + + if (needsBlending()) { + hwcl->blending = mPremultipliedAlpha ? + HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE; + } + + 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)); +} + +void Layer::setPerFrameData(hwc_layer_t* hwcl) { + sp buffer(mBufferManager.getActiveBuffer()); + if (buffer == NULL) { + // this situation can happen if we ran out of memory for instance. + // not much we can do. continue to use whatever texture was bound + // to this context. + hwcl->handle = NULL; + return; + } + hwcl->handle = const_cast(buffer->handle); + // TODO: set the crop value properly + hwcl->sourceCrop.left = 0; + hwcl->sourceCrop.top = 0; + hwcl->sourceCrop.right = buffer->width; + hwcl->sourceCrop.bottom = buffer->height; +} + void Layer::reloadTexture(const Region& dirty) { sp buffer(mBufferManager.getActiveBuffer()); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index e1d283bed..188da6a78 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -68,6 +68,8 @@ public: bool isFixedSize() const; // LayerBase interface + virtual void setGeometry(hwc_layer_t* hwcl); + virtual void setPerFrameData(hwc_layer_t* hwcl); 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 91ac915b7..043d54d96 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -307,6 +307,15 @@ void LayerBase::drawRegion(const Region& reg) const } } +void LayerBase::setGeometry(hwc_layer_t* hwcl) { + hwcl->flags |= HWC_SKIP_LAYER; +} + +void LayerBase::setPerFrameData(hwc_layer_t* hwcl) { + hwcl->compositionType = HWC_FRAMEBUFFER; + hwcl->handle = NULL; +} + void LayerBase::draw(const Region& clip) const { // reset GL state diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index 22bf85706..dd1cd05f1 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -35,6 +35,8 @@ #include +#include + #include "Transform.h" namespace android { @@ -108,6 +110,10 @@ public: virtual const char* getTypeId() const { return "LayerBase"; } + virtual void setGeometry(hwc_layer_t* hwcl); + + virtual void setPerFrameData(hwc_layer_t* hwcl); + /** * draw - performs some global clipping optimizations * and calls onDraw(). diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 637ae4827..47bb4c1b1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -52,6 +52,7 @@ #include "SurfaceFlinger.h" #include "DisplayHardware/DisplayHardware.h" +#include "DisplayHardware/HWComposer.h" /* ideally AID_GRAPHICS would be in a semi-public header * or there would be a way to map a user/group name to its id @@ -76,6 +77,7 @@ SurfaceFlinger::SurfaceFlinger() mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"), mDump("android.permission.DUMP"), mVisibleRegionsDirty(false), + mHwWorkListDirty(false), mDeferReleaseConsole(false), mFreezeDisplay(false), mFreezeCount(0), @@ -368,6 +370,11 @@ bool SurfaceFlinger::threadLoop() // post surfaces (if needed) handlePageFlip(); + if (UNLIKELY(mHwWorkListDirty)) { + // build the h/w work list + handleWorkList(); + } + const DisplayHardware& hw(graphicPlane(0).displayHardware()); if (LIKELY(hw.canDraw() && !isFrozen())) { // repaint the framebuffer (if needed) @@ -443,6 +450,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) handleTransactionLocked(transactionFlags, ditchedLayers); mLastTransactionTime = systemTime() - now; mDebugInTransaction = 0; + mHwWorkListDirty = true; // here the transaction has been committed } @@ -450,6 +458,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) * Clean-up all layers that went away * (do this without the lock held) */ + const size_t count = ditchedLayers.size(); for (size_t i=0 ; i( - mDrawingState.layersSortedByZ); + LayerVector& currentLayers( + const_cast(mDrawingState.layersSortedByZ)); visibleRegions |= lockPageFlip(currentLayers); const DisplayHardware& hw = graphicPlane(0).displayHardware(); @@ -707,6 +716,7 @@ void SurfaceFlinger::handlePageFlip() mWormholeRegion = screenRegion.subtract(opaqueRegion); mVisibleRegionsDirty = false; + mHwWorkListDirty = true; } unlockPageFlip(currentLayers); @@ -737,6 +747,21 @@ void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers) } } +void SurfaceFlinger::handleWorkList() +{ + mHwWorkListDirty = false; + HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer()); + if (hwc.initCheck() == NO_ERROR) { + const Vector< sp >& currentLayers(mVisibleLayersSortedByZ); + const size_t count = currentLayers.size(); + hwc.createWorkList(count); + HWComposer::iterator cur(hwc.begin()); + HWComposer::iterator last(hwc.end()); + for (size_t i=0 ; (isetGeometry(cur); + } + } +} void SurfaceFlinger::handleRepaint() { @@ -801,15 +826,63 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty) // draw something... drawWormhole(); } + + status_t err = NO_ERROR; const Vector< sp >& layers(mVisibleLayersSortedByZ); const size_t count = layers.size(); + + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + HWComposer& hwc(hw.getHwComposer()); + HWComposer::iterator cur(hwc.begin()); + HWComposer::iterator last(hwc.end()); + + // update the per-frame h/w composer data for each layer + if (cur != last) { + for (size_t i=0 ; isetPerFrameData(cur); + } + err = hwc.prepare(); + LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); + } + + // and then, render the layers targeted at the framebuffer + Region transparent(hw.bounds()); for (size_t i=0 ; icompositionType == HWC_FRAMEBUFFER) || + (cur->flags & HWC_SKIP_LAYER))) { + ++cur; + continue; + } + ++cur; + } + + // draw the layer into the framebuffer const sp& layer(layers[i]); + transparent.subtractSelf(layer->visibleRegionScreen); const Region clip(dirty.intersect(layer->visibleRegionScreen)); if (!clip.isEmpty()) { layer->draw(clip); } } + + // finally clear everything we didn't draw as a result of calling + // prepare (this leaves the FB transparent). + transparent.andSelf(dirty); + if (!transparent.isEmpty()) { + glClearColor(0,0,0,0); + Region::const_iterator it = transparent.begin(); + Region::const_iterator const end = transparent.end(); + const int32_t height = hw.getHeight(); + while (it != end) { + const Rect& r(*it++); + const GLint sy = height - (r.top + r.height()); + glScissor(r.left, sy, r.width(), r.height()); + glClear(GL_COLOR_BUFFER_BIT); + } + } } void SurfaceFlinger::unlockClients() diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8ecfc018e..8e286e505 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -296,6 +296,7 @@ private: void handlePageFlip(); bool lockPageFlip(const LayerVector& currentLayers); void unlockPageFlip(const LayerVector& currentLayers); + void handleWorkList(); void handleRepaint(); void postFramebuffer(); void composeSurfaces(const Region& dirty); @@ -370,6 +371,7 @@ private: Region mInvalidRegion; Region mWormholeRegion; bool mVisibleRegionsDirty; + bool mHwWorkListDirty; bool mDeferReleaseConsole; bool mFreezeDisplay; int32_t mFreezeCount;