call into hwcomposer HAL when present

Change-Id: I70f31c69a9436a43860e78977442863ecba6d27b
This commit is contained in:
Mathias Agopian 2010-08-10 17:14:02 -07:00
parent bc7e31a84b
commit a350ff9869
11 changed files with 340 additions and 7 deletions

View File

@ -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 \

View File

@ -36,11 +36,11 @@
#include "DisplayHardware/DisplayHardware.h"
#include <hardware/copybit.h>
#include <hardware/overlay.h>
#include <hardware/gralloc.h>
#include "GLExtensions.h"
#include "HWComposer.h"
using namespace android;
@ -76,7 +76,7 @@ DisplayHardware::DisplayHardware(
const sp<SurfaceFlinger>& 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

View File

@ -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<FramebufferNativeWindow> mNativeWindow;
overlay_control_device_t* mOverlayEngine;
};

View File

@ -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 <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <hardware/hardware.h>
#include <cutils/log.h>
#include <EGL/egl.h>
#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

View File

@ -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 <stdint.h>
#include <sys/types.h>
#include <EGL/egl.h>
#include <hardware/hwcomposer.h>
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

View File

@ -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<hwc_rect_t const *>(
visibleRegionScreen.getArray(
&hwcl->visibleRegionScreen.numRects));
}
void Layer::setPerFrameData(hwc_layer_t* hwcl) {
sp<GraphicBuffer> 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<native_handle_t*>(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<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());

View File

@ -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);

View File

@ -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

View File

@ -35,6 +35,8 @@
#include <pixelflinger/pixelflinger.h>
#include <hardware/hwcomposer.h>
#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().

View File

@ -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<count ; i++) {
if (ditchedLayers[i] != 0) {
@ -683,8 +692,8 @@ void SurfaceFlinger::commitTransaction()
void SurfaceFlinger::handlePageFlip()
{
bool visibleRegions = mVisibleRegionsDirty;
LayerVector& currentLayers = const_cast<LayerVector&>(
mDrawingState.layersSortedByZ);
LayerVector& currentLayers(
const_cast<LayerVector&>(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<LayerBase> >& 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 ; (i<count) && (cur!=last) ; ++i, ++cur) {
currentLayers[i]->setGeometry(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<LayerBase> >& 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 ; i<count && cur!=last ; ++i, ++cur) {
layers[i]->setPerFrameData(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 ; i<count ; ++i) {
// see if we need to skip this layer
if (!err && cur != last) {
if (!((cur->compositionType == HWC_FRAMEBUFFER) ||
(cur->flags & HWC_SKIP_LAYER))) {
++cur;
continue;
}
++cur;
}
// draw the layer into the framebuffer
const sp<LayerBase>& 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()

View File

@ -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;