one more step towards multiple display support

- remove dependency on cached state in validateVisibility
- get rid of mVertices and mTransformedBounds
- get rid of validateVisibility
- get rid of unlockPageFlip
- handleTransaction now returns a dirty region
- computevisibileregion now uses window-manager space
This commit is contained in:
Mathias Agopian 2012-06-29 14:12:52 -07:00
parent e7db724bed
commit 4fec873a98
11 changed files with 355 additions and 334 deletions

View File

@ -72,11 +72,11 @@ public:
//! returns number of items in the vector
inline size_t size() const { return VectorImpl::size(); }
//! returns wether or not the vector is empty
//! returns whether or not the vector is empty
inline bool isEmpty() const { return VectorImpl::isEmpty(); }
//! returns how many items can be stored without reallocating the backing store
inline size_t capacity() const { return VectorImpl::capacity(); }
//! setst the capacity. capacity can never be reduced less than size()
//! sets the capacity. capacity can never be reduced less than size()
inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); }
/*!
@ -102,12 +102,12 @@ public:
const TYPE& mirrorItemAt(ssize_t index) const;
/*!
* modifing the array
* modifying the array
*/
//! copy-on write support, grants write access to an item
TYPE& editItemAt(size_t index);
//! grants right acces to the top of the stack (last element)
//! grants right access to the top of the stack (last element)
TYPE& editTop();
/*!

View File

@ -145,14 +145,6 @@ void Layer::setName(const String8& name) {
mSurfaceTexture->setName(name);
}
void Layer::validateVisibility(const Transform& globalTransform, const DisplayHardware& hw) {
LayerBase::validateVisibility(globalTransform, hw);
// This optimization allows the SurfaceTexture to bake in
// the rotation so hardware overlays can be used
mSurfaceTexture->setTransformHint(getTransformHint());
}
sp<ISurface> Layer::createSurface()
{
class BSurface : public BnSurface, public LayerCleaner {
@ -225,7 +217,8 @@ Rect Layer::computeBufferCrop() const {
} else if (mActiveBuffer != NULL){
crop = Rect(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
} else {
crop = Rect(mTransformedBounds.width(), mTransformedBounds.height());
crop.makeInvalid();
return crop;
}
// ... then reduce that in the same proportions as the window crop reduces
@ -258,9 +251,11 @@ Rect Layer::computeBufferCrop() const {
return crop;
}
void Layer::setGeometry(HWComposer::HWCLayerInterface& layer)
void Layer::setGeometry(
const DisplayHardware& hw,
HWComposer::HWCLayerInterface& layer)
{
LayerBaseClient::setGeometry(layer);
LayerBaseClient::setGeometry(hw, layer);
// enable this layer
layer.setSkip(false);
@ -276,12 +271,11 @@ void Layer::setGeometry(HWComposer::HWCLayerInterface& layer)
* 1) buffer orientation/flip/mirror
* 2) state transformation (window manager)
* 3) layer orientation (screen orientation)
* mTransform is already the composition of (2) and (3)
* (NOTE: the matrices are multiplied in reverse order)
*/
const Transform bufferOrientation(mCurrentTransform);
const Transform tr(mTransform * bufferOrientation);
const Transform tr(hw.getTransform() * s.transform * bufferOrientation);
// this gives us only the "orientation" component of the transform
const uint32_t finalTransform = tr.getOrientation();
@ -339,7 +333,7 @@ void Layer::onDraw(const DisplayHardware& hw, const Region& clip) const
const sp<LayerBase>& layer(drawingLayers[i]);
if (layer.get() == static_cast<LayerBase const*>(this))
break;
under.orSelf(layer->visibleRegionScreen);
under.orSelf( hw.getTransform().transform(layer->visibleRegion) );
}
// if not everything below us is covered, we plug the holes!
Region holes(clip.subtract(under));
@ -527,10 +521,11 @@ bool Layer::onPreComposition() {
return mQueuedFrames > 0;
}
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
Region Layer::latchBuffer(bool& recomputeVisibleRegions)
{
ATRACE_CALL();
Region outDirtyRegion;
if (mQueuedFrames > 0) {
// if we've already called updateTexImage() without going through
@ -539,8 +534,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
// compositionComplete() call.
// we'll trigger an update in onPreComposition().
if (mRefreshPending) {
mPostedDirtyRegion.clear();
return;
return outDirtyRegion;
}
// Capture the old state of the layer for comparisons later
@ -637,17 +631,21 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
Reject r(mDrawingState, currentState(), recomputeVisibleRegions);
// XXX: not sure if setTransformHint belongs here
// it should only be needed when the main screen orientation changes
mSurfaceTexture->setTransformHint(getTransformHint());
if (mSurfaceTexture->updateTexImage(&r) < NO_ERROR) {
// something happened!
recomputeVisibleRegions = true;
return;
return outDirtyRegion;
}
// update the active buffer
mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
if (mActiveBuffer == NULL) {
// this can only happen if the very first buffer was rejected.
return;
return outDirtyRegion;
}
mRefreshPending = true;
@ -686,38 +684,17 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
recomputeVisibleRegions = true;
}
// FIXME: mPostedDirtyRegion = dirty & bounds
const Layer::State& front(drawingState());
mPostedDirtyRegion.set(front.active.w, front.active.h);
glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// FIXME: postedRegion should be dirty & bounds
const Layer::State& front(drawingState());
Region dirtyRegion(Rect(front.active.w, front.active.h));
// transform the dirty region to window-manager space
outDirtyRegion = (front.transform.transform(dirtyRegion));
}
}
void Layer::unlockPageFlip(
const Transform& planeTransform, Region& outDirtyRegion)
{
ATRACE_CALL();
Region postedRegion(mPostedDirtyRegion);
if (!postedRegion.isEmpty()) {
mPostedDirtyRegion.clear();
if (!visibleRegionScreen.isEmpty()) {
// The dirty region is given in the layer's coordinate space
// transform the dirty region by the surface's transformation
// and the global transformation.
const Layer::State& s(drawingState());
const Transform tr(planeTransform * s.transform);
postedRegion = tr.transform(postedRegion);
// At this point, the dirty region is in screen space.
// Make sure it's constrained by the visible region (which
// is in screen space as well).
postedRegion.andSelf(visibleRegionScreen);
outDirtyRegion.orSelf(postedRegion);
}
}
return outDirtyRegion;
}
void Layer::dump(String8& result, char* buffer, size_t SIZE) const
@ -786,7 +763,14 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const
uint32_t Layer::getTransformHint() const {
uint32_t orientation = 0;
if (!mFlinger->mDebugDisableTransformHint) {
orientation = getPlaneOrientation();
// The transform hint is used to improve performance on the main
// display -- we can only have a single transform hint, it cannot
// apply to all displays.
// This is why we use the default display here. This is not an
// oversight.
const DisplayHardware& hw(mFlinger->getDefaultDisplayHardware());
const Transform& planeTransform(hw.getTransform());
orientation = planeTransform.getOrientation();
if (orientation & Transform::ROT_INVALID) {
orientation = 0;
}

View File

@ -64,20 +64,20 @@ public:
bool isFixedSize() const;
// LayerBase interface
virtual void setGeometry(HWComposer::HWCLayerInterface& layer);
virtual void setGeometry(const DisplayHardware& hw,
HWComposer::HWCLayerInterface& layer);
virtual void setPerFrameData(HWComposer::HWCLayerInterface& layer);
virtual void setAcquireFence(HWComposer::HWCLayerInterface& layer);
virtual void onDraw(const DisplayHardware& hw, const Region& clip) const;
virtual uint32_t doTransaction(uint32_t transactionFlags);
virtual void lockPageFlip(bool& recomputeVisibleRegions);
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
virtual Region latchBuffer(bool& recomputeVisibleRegions);
virtual bool isOpaque() const;
virtual bool isSecure() const { return mSecure; }
virtual bool isProtected() const;
virtual void onRemoved();
virtual sp<Layer> getLayer() const { return const_cast<Layer*>(this); }
virtual void setName(const String8& name);
virtual void validateVisibility(const Transform& globalTransform, const DisplayHardware& hw);
// LayerBaseClient interface
virtual wp<IBinder> getSurfaceTextureBinder() const;
@ -142,7 +142,6 @@ private:
// page-flip thread (currently main thread)
bool mSecure; // no screenshots
bool mProtectedByApp; // application requires protected path to external sink
Region mPostedDirtyRegion;
};
// ---------------------------------------------------------------------------

View File

@ -45,8 +45,6 @@ LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
sequence(uint32_t(android_atomic_inc(&sSequence))),
mFlinger(flinger), mFiltering(false),
mNeedsFiltering(false),
mOrientation(0),
mPlaneOrientation(0),
mTransactionFlags(0),
mPremultipliedAlpha(true), mName("unnamed"), mDebug(false)
{
@ -170,19 +168,14 @@ bool LayerBase::setCrop(const Rect& crop) {
return true;
}
Rect LayerBase::visibleBounds() const
{
return mTransformedBounds;
}
void LayerBase::setVisibleRegion(const Region& visibleRegion) {
// always called from main thread
visibleRegionScreen = visibleRegion;
this->visibleRegion = visibleRegion;
}
void LayerBase::setCoveredRegion(const Region& coveredRegion) {
// always called from main thread
coveredRegionScreen = coveredRegion;
this->coveredRegion = coveredRegion;
}
uint32_t LayerBase::doTransaction(uint32_t flags)
@ -219,57 +212,45 @@ uint32_t LayerBase::doTransaction(uint32_t flags)
return flags;
}
void LayerBase::validateVisibility(const Transform& planeTransform, const DisplayHardware& hw)
void LayerBase::computeGeometry(const DisplayHardware& hw, LayerMesh* mesh) const
{
const Layer::State& s(drawingState());
const Transform tr(planeTransform * s.transform);
const bool transformed = tr.transformed();
const Transform tr(hw.getTransform() * s.transform);
const uint32_t hw_h = hw.getHeight();
const Rect& crop(s.active.crop);
Rect win(s.active.w, s.active.h);
if (!crop.isEmpty()) {
win.intersect(crop, &win);
}
mNumVertices = 4;
tr.transform(mVertices[0], win.left, win.top);
tr.transform(mVertices[1], win.left, win.bottom);
tr.transform(mVertices[2], win.right, win.bottom);
tr.transform(mVertices[3], win.right, win.top);
for (size_t i=0 ; i<4 ; i++)
mVertices[i][1] = hw_h - mVertices[i][1];
if (CC_UNLIKELY(transformed)) {
// NOTE: here we could also punt if we have too many rectangles
// in the transparent region
if (tr.preserveRects()) {
// transform the transparent region
transparentRegionScreen = tr.transform(s.transparentRegion);
} else {
// transformation too complex, can't do the transparent region
// optimization.
transparentRegionScreen.clear();
if (mesh) {
tr.transform(mesh->mVertices[0], win.left, win.top);
tr.transform(mesh->mVertices[1], win.left, win.bottom);
tr.transform(mesh->mVertices[2], win.right, win.bottom);
tr.transform(mesh->mVertices[3], win.right, win.top);
for (size_t i=0 ; i<4 ; i++) {
mesh->mVertices[i][1] = hw_h - mesh->mVertices[i][1];
}
} else {
transparentRegionScreen = s.transparentRegion;
}
// cache a few things...
mOrientation = tr.getOrientation();
mPlaneOrientation = planeTransform.getOrientation();
mTransform = tr;
mTransformedBounds = tr.transform(win);
}
void LayerBase::lockPageFlip(bool& recomputeVisibleRegions) {
Rect LayerBase::computeBounds() const {
const Layer::State& s(drawingState());
const Rect& crop(s.active.crop);
Rect win(s.active.w, s.active.h);
if (!crop.isEmpty()) {
win.intersect(crop, &win);
}
return s.transform.transform(win);
}
void LayerBase::unlockPageFlip(
const Transform& planeTransform, Region& outDirtyRegion) {
Region LayerBase::latchBuffer(bool& recomputeVisibleRegions) {
Region result;
return result;
}
void LayerBase::setGeometry(HWComposer::HWCLayerInterface& layer)
void LayerBase::setGeometry(
const DisplayHardware& hw,
HWComposer::HWCLayerInterface& layer)
{
layer.setDefaultState();
@ -289,10 +270,14 @@ void LayerBase::setGeometry(HWComposer::HWCLayerInterface& layer)
HWC_BLENDING_COVERAGE);
}
// scaling is already applied in mTransformedBounds
layer.setFrame(mTransformedBounds);
layer.setVisibleRegionScreen(visibleRegionScreen);
layer.setCrop(mTransformedBounds.getBounds());
const Transform& tr = hw.getTransform();
Rect transformedBounds(computeBounds());
transformedBounds = tr.transform(transformedBounds);
// scaling is already applied in transformedBounds
layer.setFrame(transformedBounds);
layer.setCrop(transformedBounds.getBounds());
layer.setVisibleRegionScreen(tr.transform(visibleRegion));
}
void LayerBase::setPerFrameData(HWComposer::HWCLayerInterface& layer) {
@ -335,8 +320,11 @@ void LayerBase::clearWithOpenGL(const DisplayHardware& hw, const Region& clip,
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glVertexPointer(2, GL_FLOAT, 0, mVertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices);
LayerMesh mesh;
computeGeometry(hw, &mesh);
glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
}
void LayerBase::clearWithOpenGL(const DisplayHardware& hw, const Region& clip) const
@ -371,6 +359,12 @@ void LayerBase::drawWithOpenGL(const DisplayHardware& hw, const Region& clip) co
}
}
LayerMesh mesh;
computeGeometry(hw, &mesh);
// TODO: we probably want to generate the texture coords with the mesh
// here we assume that we only have 4 vertices
struct TexCoords {
GLfloat u;
GLfloat v;
@ -380,9 +374,9 @@ void LayerBase::drawWithOpenGL(const DisplayHardware& hw, const Region& clip) co
if (!s.active.crop.isEmpty()) {
crop = s.active.crop;
}
GLfloat left = GLfloat(crop.left) / GLfloat(s.active.w);
GLfloat top = GLfloat(crop.top) / GLfloat(s.active.h);
GLfloat right = GLfloat(crop.right) / GLfloat(s.active.w);
GLfloat left = GLfloat(crop.left) / GLfloat(s.active.w);
GLfloat top = GLfloat(crop.top) / GLfloat(s.active.h);
GLfloat right = GLfloat(crop.right) / GLfloat(s.active.w);
GLfloat bottom = GLfloat(crop.bottom) / GLfloat(s.active.h);
TexCoords texCoords[4];
@ -399,9 +393,9 @@ void LayerBase::drawWithOpenGL(const DisplayHardware& hw, const Region& clip) co
}
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, mVertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices);
glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_BLEND);
@ -417,8 +411,7 @@ void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
result.append(buffer);
s.transparentRegion.dump(result, "transparentRegion");
transparentRegionScreen.dump(result, "transparentRegionScreen");
visibleRegionScreen.dump(result, "visibleRegionScreen");
visibleRegion.dump(result, "visibleRegion");
snprintf(buffer, SIZE,
" "

View File

@ -57,9 +57,9 @@ public:
DisplayID dpy;
mutable bool contentDirty;
Region visibleRegionScreen;
Region transparentRegionScreen;
Region coveredRegionScreen;
// regions below are in window-manager space
Region visibleRegion;
Region coveredRegion;
int32_t sequence;
struct Geometry {
@ -86,6 +86,20 @@ public:
Region transparentRegion;
};
class LayerMesh {
friend class LayerBase;
GLfloat mVertices[4][2];
size_t mNumVertices;
public:
LayerMesh() : mNumVertices(4) { }
GLfloat const* getVertices() const {
return &mVertices[0][0];
}
size_t getVertexCount() const {
return mNumVertices;
}
};
virtual void setName(const String8& name);
String8 getName() const;
@ -105,15 +119,18 @@ public:
uint32_t getTransactionFlags(uint32_t flags);
uint32_t setTransactionFlags(uint32_t flags);
Rect visibleBounds() const;
void computeGeometry(const DisplayHardware& hw, LayerMesh* mesh) const;
Rect computeBounds() const;
virtual sp<LayerBaseClient> getLayerBaseClient() const { return 0; }
virtual sp<Layer> getLayer() const { return 0; }
virtual const char* getTypeId() const { return "LayerBase"; }
virtual void setGeometry(HWComposer::HWCLayerInterface& layer);
virtual void setGeometry(const DisplayHardware& hw,
HWComposer::HWCLayerInterface& layer);
virtual void setPerFrameData(HWComposer::HWCLayerInterface& layer);
virtual void setAcquireFence(HWComposer::HWCLayerInterface& layer);
@ -156,26 +173,13 @@ public:
virtual void setCoveredRegion(const Region& coveredRegion);
/**
* validateVisibility - cache a bunch of things
*/
virtual void validateVisibility(const Transform& globalTransform, const DisplayHardware& hw);
/**
* lockPageFlip - called each time the screen is redrawn and returns whether
* latchBuffer - called each time the screen is redrawn and returns whether
* the visible regions need to be recomputed (this is a fairly heavy
* operation, so this should be set only if needed). Typically this is used
* to figure out if the content or size of a surface has changed.
*/
virtual void lockPageFlip(bool& recomputeVisibleRegions);
/**
* unlockPageFlip - called each time the screen is redrawn. updates the
* final dirty region wrt the planeTransform.
* At this point, all visible regions, surface position and size, etc... are
* correct.
*/
virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
virtual Region latchBuffer(bool& recomputeVisibleRegions);
/**
* isOpaque - true if this surface is opaque
*/
@ -233,9 +237,6 @@ public:
inline const State& currentState() const { return mCurrentState; }
inline State& currentState() { return mCurrentState; }
int32_t getOrientation() const { return mOrientation; }
int32_t getPlaneOrientation() const { return mPlaneOrientation; }
void clearWithOpenGL(const DisplayHardware& hw, const Region& clip) const;
protected:
@ -253,19 +254,10 @@ private:
// Whether filtering is forced on or not
bool mFiltering;
// cached during validateVisibility()
// Whether filtering is needed b/c of the drawingstate
bool mNeedsFiltering;
protected:
// cached during validateVisibility()
int32_t mOrientation;
int32_t mPlaneOrientation;
Transform mTransform;
GLfloat mVertices[4][2];
size_t mNumVertices;
Rect mTransformedBounds;
// these are protected by an external lock
State mCurrentState;
State mDrawingState;

View File

@ -58,8 +58,11 @@ void LayerDim::onDraw(const DisplayHardware& hw, const Region& clip) const
glColor4f(0, 0, 0, alpha);
glVertexPointer(2, GL_FLOAT, 0, mVertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
LayerMesh mesh;
computeGeometry(hw, &mesh);
glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
glDisable(GL_BLEND);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

View File

@ -120,6 +120,9 @@ void LayerScreenshot::onDraw(const DisplayHardware& hw, const Region& clip) cons
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
LayerMesh mesh;
computeGeometry(hw, &mesh);
glColor4f(0, 0, 0, alpha);
glDisable(GL_TEXTURE_EXTERNAL_OES);
@ -133,8 +136,8 @@ void LayerScreenshot::onDraw(const DisplayHardware& hw, const Region& clip) cons
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, mTexCoords);
glVertexPointer(2, GL_FLOAT, 0, mVertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices);
glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);

View File

@ -49,13 +49,13 @@ void MessageBase::handleMessage(const Message&) {
// ---------------------------------------------------------------------------
void MessageQueue::Handler::signalRefresh() {
void MessageQueue::Handler::dispatchRefresh() {
if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
}
}
void MessageQueue::Handler::signalInvalidate() {
void MessageQueue::Handler::dispatchInvalidate() {
if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
}
@ -132,13 +132,31 @@ status_t MessageQueue::postMessage(
return NO_ERROR;
}
/* when INVALIDATE_ON_VSYNC is set SF only processes
* buffer updates on VSYNC and performs a refresh immediately
* after.
*
* when INVALIDATE_ON_VSYNC is set to false, SF will instead
* perform the buffer updates immediately, but the refresh only
* at the next VSYNC.
* THIS MODE IS BUGGY ON GALAXY NEXUS AND WILL CAUSE HANGS
*/
#define INVALIDATE_ON_VSYNC 1
void MessageQueue::invalidate() {
// mHandler->signalInvalidate();
#if INVALIDATE_ON_VSYNC
mEvents->requestNextVsync();
#else
mHandler->dispatchInvalidate();
#endif
}
void MessageQueue::refresh() {
#if INVALIDATE_ON_VSYNC
mHandler->dispatchRefresh();
#else
mEvents->requestNextVsync();
#endif
}
int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
@ -152,7 +170,11 @@ int MessageQueue::eventReceiver(int fd, int events) {
while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
for (int i=0 ; i<n ; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
mHandler->signalRefresh();
#if INVALIDATE_ON_VSYNC
mHandler->dispatchInvalidate();
#else
mHandler->dispatchRefresh();
#endif
break;
}
}

View File

@ -70,8 +70,8 @@ class MessageQueue {
public:
Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
virtual void handleMessage(const Message& message);
void signalRefresh();
void signalInvalidate();
void dispatchRefresh();
void dispatchInvalidate();
};
friend class Handler;

View File

@ -425,100 +425,117 @@ status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
return res;
}
bool SurfaceFlinger::threadLoop()
{
bool SurfaceFlinger::threadLoop() {
waitForEvent();
return true;
}
void SurfaceFlinger::onMessageReceived(int32_t what)
{
void SurfaceFlinger::onMessageReceived(int32_t what) {
ATRACE_CALL();
switch (what) {
case MessageQueue::REFRESH: {
// case MessageQueue::INVALIDATE: {
// if we're in a global transaction, don't do anything.
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
uint32_t transactionFlags = peekTransactionFlags(mask);
if (CC_UNLIKELY(transactionFlags)) {
handleTransaction(transactionFlags);
}
// post surfaces (if needed)
handlePageFlip();
// signalRefresh();
//
// } break;
//
// case MessageQueue::REFRESH: {
handleRefresh();
// TODO: iterate through all displays
const DisplayHardware& hw(getDisplayHardware(0));
// if (mDirtyRegion.isEmpty()) {
// return;
// }
if (CC_UNLIKELY(mHwWorkListDirty)) {
// build the h/w work list
handleWorkList(hw);
}
if (CC_LIKELY(hw.canDraw())) {
// repaint the framebuffer (if needed)
handleRepaint(hw);
// inform the h/w that we're done compositing
hw.compositionComplete();
postFramebuffer();
} else {
// pretend we did the post
hw.compositionComplete();
}
// render to the external display if we have one
EGLSurface externalDisplaySurface = getExternalDisplaySurface();
if (externalDisplaySurface != EGL_NO_SURFACE) {
EGLSurface cur = eglGetCurrentSurface(EGL_DRAW);
EGLBoolean success = eglMakeCurrent(eglGetCurrentDisplay(),
externalDisplaySurface, externalDisplaySurface,
eglGetCurrentContext());
ALOGE_IF(!success, "eglMakeCurrent -> external failed");
if (success) {
// redraw the screen entirely...
glDisable(GL_TEXTURE_EXTERNAL_OES);
glDisable(GL_TEXTURE_2D);
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer(layers[i]);
layer->drawForSreenShot(hw);
}
success = eglSwapBuffers(eglGetCurrentDisplay(), externalDisplaySurface);
ALOGE_IF(!success, "external display eglSwapBuffers failed");
hw.compositionComplete();
}
success = eglMakeCurrent(eglGetCurrentDisplay(),
cur, cur, eglGetCurrentContext());
ALOGE_IF(!success, "eglMakeCurrent -> internal failed");
}
} break;
case MessageQueue::INVALIDATE:
handleMessageTransaction();
handleMessageInvalidate();
signalRefresh();
break;
case MessageQueue::REFRESH:
handleMessageRefresh();
break;
}
}
void SurfaceFlinger::handleMessageTransaction() {
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
uint32_t transactionFlags = peekTransactionFlags(mask);
if (transactionFlags) {
Region dirtyRegion;
dirtyRegion = handleTransaction(transactionFlags);
// XXX: dirtyRegion should be per screen
mDirtyRegion |= dirtyRegion;
}
}
void SurfaceFlinger::handleMessageInvalidate() {
Region dirtyRegion;
dirtyRegion = handlePageFlip();
// XXX: dirtyRegion should be per screen
mDirtyRegion |= dirtyRegion;
}
void SurfaceFlinger::handleMessageRefresh() {
handleRefresh();
// XXX: dirtyRegion should be per screen, we should check all of them
if (mDirtyRegion.isEmpty()) {
return;
}
// TODO: iterate through all displays
const DisplayHardware& hw(getDisplayHardware(0));
// XXX: dirtyRegion should be per screen
// transform the dirty region into this screen's coordinate space
const Transform& planeTransform(hw.getTransform());
mDirtyRegion = planeTransform.transform(mDirtyRegion);
mDirtyRegion.orSelf(getAndClearInvalidateRegion());
mDirtyRegion.andSelf(hw.bounds());
if (CC_UNLIKELY(mHwWorkListDirty)) {
// build the h/w work list
handleWorkList(hw);
}
if (CC_LIKELY(hw.canDraw())) {
// repaint the framebuffer (if needed)
handleRepaint(hw);
// inform the h/w that we're done compositing
hw.compositionComplete();
postFramebuffer();
} else {
// pretend we did the post
hw.compositionComplete();
}
// render to the external display if we have one
EGLSurface externalDisplaySurface = getExternalDisplaySurface();
if (externalDisplaySurface != EGL_NO_SURFACE) {
EGLSurface cur = eglGetCurrentSurface(EGL_DRAW);
EGLBoolean success = eglMakeCurrent(eglGetCurrentDisplay(),
externalDisplaySurface, externalDisplaySurface,
eglGetCurrentContext());
ALOGE_IF(!success, "eglMakeCurrent -> external failed");
if (success) {
// redraw the screen entirely...
glDisable(GL_TEXTURE_EXTERNAL_OES);
glDisable(GL_TEXTURE_2D);
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer(layers[i]);
layer->drawForSreenShot(hw);
}
success = eglSwapBuffers(eglGetCurrentDisplay(), externalDisplaySurface);
ALOGE_IF(!success, "external display eglSwapBuffers failed");
hw.compositionComplete();
}
success = eglMakeCurrent(eglGetCurrentDisplay(),
cur, cur, eglGetCurrentContext());
ALOGE_IF(!success, "eglMakeCurrent -> internal failed");
}
}
void SurfaceFlinger::postFramebuffer()
{
ATRACE_CALL();
@ -564,10 +581,12 @@ void SurfaceFlinger::postFramebuffer()
mSwapRegion.clear();
}
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
Region SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
ATRACE_CALL();
Region dirtyRegion;
Mutex::Autolock _l(mStateLock);
const nsecs_t now = systemTime();
mDebugInTransaction = now;
@ -580,16 +599,19 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
transactionFlags = getTransactionFlags(mask);
handleTransactionLocked(transactionFlags);
dirtyRegion = handleTransactionLocked(transactionFlags);
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
invalidateHwcGeometry();
// here the transaction has been committed
return dirtyRegion;
}
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
Region SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
Region dirtyRegion;
const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
const size_t count = currentLayers.size();
@ -652,13 +674,34 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
const sp<LayerBase>& layer(previousLayers[i]);
if (currentLayers.indexOf( layer ) < 0) {
// this layer is not visible anymore
mDirtyRegionRemovedLayer.orSelf(layer->visibleRegionScreen);
// TODO: we could traverse the tree from front to back and compute the actual visible region
// TODO: we could cache the transformed region
Layer::State front(layer->drawingState());
Region visibleReg = front.transform.transform(
Region(Rect(front.active.w, front.active.h)));
dirtyRegion.orSelf(visibleReg);
}
}
}
}
commitTransaction();
return dirtyRegion;
}
void SurfaceFlinger::commitTransaction()
{
if (!mLayersPendingRemoval.isEmpty()) {
// Notify removed layers now that they can't be drawn from
for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) {
mLayersPendingRemoval[i]->onRemoved();
}
mLayersPendingRemoval.clear();
}
mDrawingState = mCurrentState;
mTransationPending = false;
mTransactionCV.broadcast();
}
void SurfaceFlinger::computeVisibleRegions(
@ -666,10 +709,6 @@ void SurfaceFlinger::computeVisibleRegions(
{
ATRACE_CALL();
const DisplayHardware& hw(getDefaultDisplayHardware()); // FIXME: we shouldn't rely on DisplayHardware here
const Transform& planeTransform(hw.getTransform());
const Region screenRegion(hw.bounds());
Region aboveOpaqueLayers;
Region aboveCoveredLayers;
Region dirty;
@ -679,7 +718,6 @@ void SurfaceFlinger::computeVisibleRegions(
size_t i = currentLayers.size();
while (i--) {
const sp<LayerBase>& layer = currentLayers[i];
layer->validateVisibility(planeTransform, hw);
// start with the whole surface at its current location
const Layer::State& s(layer->drawingState());
@ -707,17 +745,30 @@ void SurfaceFlinger::computeVisibleRegions(
// handle hidden surfaces by setting the visible region to empty
if (CC_LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) {
const bool translucent = !layer->isOpaque();
const Rect bounds(layer->visibleBounds());
Rect bounds(layer->computeBounds());
visibleRegion.set(bounds);
visibleRegion.andSelf(screenRegion);
if (!visibleRegion.isEmpty()) {
// Remove the transparent area from the visible region
if (translucent) {
visibleRegion.subtractSelf(layer->transparentRegionScreen);
Region transparentRegionScreen;
const Transform tr(s.transform);
if (tr.transformed()) {
if (tr.preserveRects()) {
// transform the transparent region
transparentRegionScreen = tr.transform(s.transparentRegion);
} else {
// transformation too complex, can't do the
// transparent region optimization.
transparentRegionScreen.clear();
}
} else {
transparentRegionScreen = s.transparentRegion;
}
visibleRegion.subtractSelf(transparentRegionScreen);
}
// compute the opaque region
const int32_t layerOrientation = layer->getOrientation();
const int32_t layerOrientation = s.transform.getOrientation();
if (s.alpha==255 && !translucent &&
((layerOrientation & Transform::ROT_INVALID) == false)) {
// the opaque region is the layer's footprint
@ -740,7 +791,7 @@ void SurfaceFlinger::computeVisibleRegions(
// we need to invalidate the whole region
dirty = visibleRegion;
// as well, as the old visible region
dirty.orSelf(layer->visibleRegionScreen);
dirty.orSelf(layer->visibleRegion);
layer->contentDirty = false;
} else {
/* compute the exposed region:
@ -756,8 +807,8 @@ void SurfaceFlinger::computeVisibleRegions(
* exposed because of a resize.
*/
const Region newExposed = visibleRegion - coveredRegion;
const Region oldVisibleRegion = layer->visibleRegionScreen;
const Region oldCoveredRegion = layer->coveredRegionScreen;
const Region oldVisibleRegion = layer->visibleRegion;
const Region oldCoveredRegion = layer->coveredRegion;
const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
}
@ -779,63 +830,51 @@ void SurfaceFlinger::computeVisibleRegions(
}
}
// invalidate the areas where a layer was removed
dirtyRegion.orSelf(mDirtyRegionRemovedLayer);
mDirtyRegionRemovedLayer.clear();
mSecureFrameBuffer = secureFrameBuffer;
opaqueRegion = aboveOpaqueLayers;
}
void SurfaceFlinger::commitTransaction()
{
if (!mLayersPendingRemoval.isEmpty()) {
// Notify removed layers now that they can't be drawn from
for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) {
mLayersPendingRemoval[i]->onRemoved();
}
mLayersPendingRemoval.clear();
}
mDrawingState = mCurrentState;
mTransationPending = false;
mTransactionCV.broadcast();
}
void SurfaceFlinger::handlePageFlip()
Region SurfaceFlinger::handlePageFlip()
{
ATRACE_CALL();
const DisplayHardware& hw(getDefaultDisplayHardware()); // FIXME: it's a problem we need DisplayHardware here
const Region screenRegion(hw.bounds());
Region dirtyRegion;
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
const bool visibleRegions = lockPageFlip(currentLayers);
if (visibleRegions || mVisibleRegionsDirty) {
Region opaqueRegion;
computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
bool visibleRegions = false;
const size_t count = currentLayers.size();
sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(layers[i]);
dirtyRegion.orSelf( layer->latchBuffer(visibleRegions) );
}
/*
* rebuild the visible layer list
*/
const size_t count = currentLayers.size();
mVisibleLayersSortedByZ.clear();
mVisibleLayersSortedByZ.setCapacity(count);
for (size_t i=0 ; i<count ; i++) {
if (!currentLayers[i]->visibleRegionScreen.isEmpty())
mVisibleLayersSortedByZ.add(currentLayers[i]);
}
if (visibleRegions || mVisibleRegionsDirty) {
Region opaqueRegion;
computeVisibleRegions(currentLayers, dirtyRegion, opaqueRegion);
mWormholeRegion = screenRegion.subtract(opaqueRegion);
mVisibleRegionsDirty = false;
invalidateHwcGeometry();
/*
* rebuild the visible layer list
*/
// XXX: mVisibleLayersSortedByZ should be per-screen
const size_t count = currentLayers.size();
mVisibleLayersSortedByZ.clear();
mVisibleLayersSortedByZ.setCapacity(count);
for (size_t i=0 ; i<count ; i++) {
if (!currentLayers[i]->visibleRegion.isEmpty())
mVisibleLayersSortedByZ.add(currentLayers[i]);
}
unlockPageFlip(currentLayers);
// FIXME: mWormholeRegion needs to be calculated per screen
const DisplayHardware& hw(getDefaultDisplayHardware()); // XXX: we can't keep that here
mWormholeRegion = Region(hw.getBounds()).subtract(
hw.getTransform().transform(opaqueRegion) );
mVisibleRegionsDirty = false;
invalidateHwcGeometry();
}
mDirtyRegion.orSelf(getAndClearInvalidateRegion());
mDirtyRegion.andSelf(screenRegion);
return dirtyRegion;
}
void SurfaceFlinger::invalidateHwcGeometry()
@ -843,30 +882,6 @@ void SurfaceFlinger::invalidateHwcGeometry()
mHwWorkListDirty = true;
}
bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers)
{
bool recomputeVisibleRegions = false;
size_t count = currentLayers.size();
sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(layers[i]);
layer->lockPageFlip(recomputeVisibleRegions);
}
return recomputeVisibleRegions;
}
void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)
{
const DisplayHardware& hw(getDefaultDisplayHardware()); // FIXME: it's a problem we need DisplayHardware here
const Transform& planeTransform(hw.getTransform());
const size_t count = currentLayers.size();
sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(layers[i]);
layer->unlockPageFlip(planeTransform, mDirtyRegion);
}
}
void SurfaceFlinger::handleRefresh()
{
bool needInvalidate = false;
@ -896,7 +911,7 @@ void SurfaceFlinger::handleWorkList(const DisplayHardware& hw)
HWComposer::LayerListIterator cur = hwc.begin();
const HWComposer::LayerListIterator end = hwc.end();
for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
currentLayers[i]->setGeometry(*cur);
currentLayers[i]->setGeometry(hw, *cur);
if (mDebugDisableHWC || mDebugRegion) {
cur->setSkip(true);
}
@ -1012,9 +1027,10 @@ void SurfaceFlinger::composeSurfaces(const DisplayHardware& hw, const Region& di
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
const size_t count = layers.size();
const Transform& tr = hw.getTransform();
for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
const sp<LayerBase>& layer(layers[i]);
const Region clip(dirty.intersect(layer->visibleRegionScreen));
const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
if (!clip.isEmpty()) {
if (cur->getCompositionType() == HWC_OVERLAY) {
if (i && (cur->getHints() & HWC_HINT_CLEAR_FB)

View File

@ -129,6 +129,9 @@ public:
GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
void onMessageReceived(int32_t what);
void handleMessageTransaction();
void handleMessageInvalidate();
void handleMessageRefresh();
status_t postMessageAsync(const sp<MessageBase>& msg,
nsecs_t reltime=0, uint32_t flags = 0);
@ -237,17 +240,23 @@ public: // hack to work around gcc 4.0.3 bug
private:
void waitForEvent();
void handleTransaction(uint32_t transactionFlags);
void handleTransactionLocked(uint32_t transactionFlags);
Region handleTransaction(uint32_t transactionFlags);
Region handleTransactionLocked(uint32_t transactionFlags);
void computeVisibleRegions(
const LayerVector& currentLayers,
Region& dirtyRegion,
Region& wormholeRegion);
void handlePageFlip();
bool lockPageFlip(const LayerVector& currentLayers);
void unlockPageFlip(const LayerVector& currentLayers);
/* handlePageFilp: this is were we latch a new buffer
* if available and compute the dirty region.
* The return value is the dirty region expressed in the
* window manager's coordinate space (or the layer's state
* space, which is the same thing), in particular the dirty
* region is independent from a specific display's orientation.
*/
Region handlePageFlip();
void handleRefresh();
void handleWorkList(const DisplayHardware& hw);
void handleRepaint(const DisplayHardware& hw);