Get rid of LayerBase.

The functionality of LayerBase and Layer is folded
into Layer. There wasn't a need for this abstraction
anymore.

Change-Id: I66511c08cc3d89009ba4deabf47e26cd4cfeaefb
This commit is contained in:
Mathias Agopian 2013-03-05 17:47:11 -08:00
parent 2f73af9212
commit 13127d8921
14 changed files with 959 additions and 1254 deletions

View File

@ -7,7 +7,6 @@ LOCAL_SRC_FILES:= \
EventThread.cpp \
FrameTracker.cpp \
Layer.cpp \
LayerBase.cpp \
LayerDim.cpp \
DisplayHardware/FramebufferSurface.cpp \
DisplayHardware/HWComposer.cpp \

View File

@ -23,7 +23,6 @@
#include "Client.h"
#include "Layer.h"
#include "LayerBase.h"
#include "SurfaceFlinger.h"
namespace android {
@ -43,7 +42,7 @@ Client::~Client()
{
const size_t count = mLayers.size();
for (size_t i=0 ; i<count ; i++) {
sp<LayerBase> layer(mLayers.valueAt(i).promote());
sp<Layer> layer(mLayers.valueAt(i).promote());
if (layer != 0) {
mFlinger->removeLayer(layer);
}
@ -54,13 +53,13 @@ status_t Client::initCheck() const {
return NO_ERROR;
}
void Client::attachLayer(const sp<IBinder>& handle, const sp<LayerBase>& layer)
void Client::attachLayer(const sp<IBinder>& handle, const sp<Layer>& layer)
{
Mutex::Autolock _l(mLock);
mLayers.add(handle, layer);
}
void Client::detachLayer(const LayerBase* layer)
void Client::detachLayer(const Layer* layer)
{
Mutex::Autolock _l(mLock);
// we do a linear search here, because this doesn't happen often
@ -72,11 +71,11 @@ void Client::detachLayer(const LayerBase* layer)
}
}
}
sp<LayerBase> Client::getLayerUser(const sp<IBinder>& handle) const
sp<Layer> Client::getLayerUser(const sp<IBinder>& handle) const
{
Mutex::Autolock _l(mLock);
sp<LayerBase> lbc;
wp<LayerBase> layer(mLayers.valueFor(handle));
sp<Layer> lbc;
wp<Layer> layer(mLayers.valueFor(handle));
if (layer != 0) {
lbc = layer.promote();
ALOGE_IF(lbc==0, "getLayerUser(name=%p) is dead", handle.get());

View File

@ -30,7 +30,7 @@ namespace android {
// ---------------------------------------------------------------------------
class LayerBase;
class Layer;
class SurfaceFlinger;
// ---------------------------------------------------------------------------
@ -44,11 +44,11 @@ public:
status_t initCheck() const;
// protected by SurfaceFlinger::mStateLock
void attachLayer(const sp<IBinder>& handle, const sp<LayerBase>& layer);
void attachLayer(const sp<IBinder>& handle, const sp<Layer>& layer);
void detachLayer(const LayerBase* layer);
void detachLayer(const Layer* layer);
sp<LayerBase> getLayerUser(const sp<IBinder>& handle) const;
sp<Layer> getLayerUser(const sp<IBinder>& handle) const;
private:
// ISurfaceComposerClient interface
@ -66,7 +66,7 @@ private:
sp<SurfaceFlinger> mFlinger;
// protected by mLock
DefaultKeyedVector< wp<IBinder>, wp<LayerBase> > mLayers;
DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayers;
// thread-safe
mutable Mutex mLock;

View File

@ -42,7 +42,7 @@
#include "DisplayDevice.h"
#include "GLExtensions.h"
#include "SurfaceFlinger.h"
#include "LayerBase.h"
#include "Layer.h"
// ----------------------------------------------------------------------------
using namespace android;
@ -282,19 +282,19 @@ void DisplayDevice::setViewportAndProjection(const sp<const DisplayDevice>& hw)
// ----------------------------------------------------------------------------
void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers) {
void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers) {
mVisibleLayersSortedByZ = layers;
mSecureLayerVisible = false;
size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(layers[i]);
const sp<Layer>& layer(layers[i]);
if (layer->isSecure()) {
mSecureLayerVisible = true;
}
}
}
const Vector< sp<LayerBase> >& DisplayDevice::getVisibleLayersSortedByZ() const {
const Vector< sp<Layer> >& DisplayDevice::getVisibleLayersSortedByZ() const {
return mVisibleLayersSortedByZ;
}

View File

@ -38,7 +38,7 @@ namespace android {
class DisplayInfo;
class FramebufferSurface;
class LayerBase;
class Layer;
class SurfaceFlinger;
class HWComposer;
@ -99,8 +99,8 @@ public:
EGLSurface getEGLSurface() const;
void setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers);
const Vector< sp<LayerBase> >& getVisibleLayersSortedByZ() const;
void setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
bool getSecureLayerVisible() const;
Region getDirtyRegion(bool repaintEverything) const;
@ -186,7 +186,7 @@ private:
*/
// list of visible layers on that display
Vector< sp<LayerBase> > mVisibleLayersSortedByZ;
Vector< sp<Layer> > mVisibleLayersSortedByZ;
// Whether we have a visible secure layer on this display
bool mSecureLayerVisible;

View File

@ -41,7 +41,6 @@
#include <cutils/properties.h>
#include "Layer.h" // needed only for debugging
#include "LayerBase.h"
#include "HWComposer.h"
#include "SurfaceFlinger.h"
#include <utils/CallStack.h>
@ -925,7 +924,7 @@ void HWComposer::dump(String8& result, char* buffer, size_t SIZE) const {
for (size_t i=0 ; i<mNumDisplays ; i++) {
const DisplayData& disp(mDisplayData[i]);
const Vector< sp<LayerBase> >& visibleLayersSortedByZ =
const Vector< sp<Layer> >& visibleLayersSortedByZ =
mFlinger->getLayerSortedByZForHwcDisplay(i);
if (disp.connected) {
@ -949,13 +948,11 @@ void HWComposer::dump(String8& result, char* buffer, size_t SIZE) const {
String8 name("unknown");
if (i < visibleLayersSortedByZ.size()) {
const sp<LayerBase>& layer(visibleLayersSortedByZ[i]);
if (layer->getLayer() != NULL) {
const sp<GraphicBuffer>& buffer(
layer->getLayer()->getActiveBuffer());
if (buffer != NULL) {
format = buffer->getPixelFormat();
}
const sp<Layer>& layer(visibleLayersSortedByZ[i]);
const sp<GraphicBuffer>& buffer(
layer->getActiveBuffer());
if (buffer != NULL) {
format = buffer->getPixelFormat();
}
name = layer->getName();
}

View File

@ -47,7 +47,6 @@ namespace android {
class GraphicBuffer;
class Fence;
class LayerBase;
class Region;
class String8;
class SurfaceFlinger;

View File

@ -19,6 +19,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <math.h>
#include <cutils/compiler.h>
#include <cutils/native_handle.h>
@ -49,37 +50,39 @@ namespace android {
// ---------------------------------------------------------------------------
int32_t Layer::sSequence = 1;
Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client)
: LayerBase(flinger, client),
: contentDirty(false),
sequence(uint32_t(android_atomic_inc(&sSequence))),
mFlinger(flinger),
mTextureName(-1U),
mPremultipliedAlpha(true),
mName("unnamed"),
mDebug(false),
mFormat(PIXEL_FORMAT_NONE),
mGLExtensions(GLExtensions::getInstance()),
mOpaqueLayer(true),
mTransactionFlags(0),
mQueuedFrames(0),
mCurrentTransform(0),
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mCurrentOpacity(true),
mRefreshPending(false),
mFrameLatencyNeeded(false),
mFormat(PIXEL_FORMAT_NONE),
mGLExtensions(GLExtensions::getInstance()),
mOpaqueLayer(true),
mFiltering(false),
mNeedsFiltering(false),
mSecure(false),
mProtectedByApp(false)
mProtectedByApp(false),
mHasSurface(false),
mClientRef(client)
{
mCurrentCrop.makeInvalid();
glGenTextures(1, &mTextureName);
}
void Layer::onLayerDisplayed(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface* layer) {
LayerBase::onLayerDisplayed(hw, layer);
if (layer) {
mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFenceFd());
}
}
void Layer::onFirstRef()
{
LayerBase::onFirstRef();
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<BufferQueue> bq = new SurfaceTextureLayer();
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mTextureName, true,
@ -102,9 +105,25 @@ void Layer::onFirstRef()
Layer::~Layer()
{
sp<Client> c(mClientRef.promote());
if (c != 0) {
c->detachLayer(this);
}
mFlinger->deleteTextureAsync(mTextureName);
}
// ---------------------------------------------------------------------------
// callbacks
// ---------------------------------------------------------------------------
void Layer::onLayerDisplayed(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface* layer) {
if (layer) {
layer->onDisplayed();
mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFenceFd());
}
}
void Layer::onFrameAvailable() {
android_atomic_inc(&mQueuedFrames);
mFlinger->signalLayerUpdate();
@ -112,56 +131,45 @@ void Layer::onFrameAvailable() {
// called with SurfaceFlinger::mStateLock as soon as the layer is entered
// in the purgatory list
void Layer::onRemoved()
{
void Layer::onRemoved() {
mSurfaceFlingerConsumer->abandon();
}
// ---------------------------------------------------------------------------
// set-up
// ---------------------------------------------------------------------------
void Layer::setName(const String8& name) {
LayerBase::setName(name);
mName = name;
mSurfaceFlingerConsumer->setName(name);
}
sp<ISurface> Layer::createSurface()
{
/*
* This class provides an implementation of BnSurface (the "native" or
* "remote" side of the Binder IPC interface ISurface), and mixes in
* LayerCleaner to ensure that mFlinger->onLayerDestroyed() is called for
* this layer when the BSurface is destroyed.
*
* The idea is to provide a handle to the Layer through ISurface that
* is cleaned up automatically when the last reference to the ISurface
* goes away. (The references will be held on the "proxy" side, while
* the Layer exists on the "native" side.)
*
* The Layer has a reference to an instance of SurfaceFlinger's variant
* of GLConsumer, which holds a reference to the BufferQueue. The
* getSurfaceTexture() call returns a Binder interface reference for
* the producer interface of the buffer queue associated with the Layer.
*/
class BSurface : public BnSurface, public LayerCleaner {
wp<const Layer> mOwner;
virtual sp<IGraphicBufferProducer> getSurfaceTexture() const {
sp<IGraphicBufferProducer> res;
sp<const Layer> that( mOwner.promote() );
if (that != NULL) {
res = that->mSurfaceFlingerConsumer->getBufferQueue();
}
return res;
}
public:
BSurface(const sp<SurfaceFlinger>& flinger,
const sp<Layer>& layer)
: LayerCleaner(flinger, layer), mOwner(layer) { }
};
sp<ISurface> sur(new BSurface(mFlinger, this));
return sur;
String8 Layer::getName() const {
return mName;
}
wp<IBinder> Layer::getSurfaceTextureBinder() const
void Layer::initStates(uint32_t w, uint32_t h, uint32_t flags)
{
return mSurfaceFlingerConsumer->getBufferQueue()->asBinder();
uint32_t layerFlags = 0;
if (flags & ISurfaceComposerClient::eHidden)
layerFlags = layer_state_t::eLayerHidden;
if (flags & ISurfaceComposerClient::eNonPremultiplied)
mPremultipliedAlpha = false;
mCurrentState.active.w = w;
mCurrentState.active.h = h;
mCurrentState.active.crop.makeInvalid();
mCurrentState.z = 0;
mCurrentState.alpha = 0xFF;
mCurrentState.layerStack = 0;
mCurrentState.flags = layerFlags;
mCurrentState.sequence = 0;
mCurrentState.transform.set(0, 0);
mCurrentState.requested = mCurrentState.active;
// drawing state & current state are identical
mDrawingState = mCurrentState;
}
status_t Layer::setBuffers( uint32_t w, uint32_t h,
@ -199,6 +207,63 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,
return NO_ERROR;
}
sp<ISurface> Layer::createSurface() {
/*
* This class provides an implementation of BnSurface (the "native" or
* "remote" side of the Binder IPC interface ISurface), and mixes in
* LayerCleaner to ensure that mFlinger->onLayerDestroyed() is called for
* this layer when the BSurface is destroyed.
*
* The idea is to provide a handle to the Layer through ISurface that
* is cleaned up automatically when the last reference to the ISurface
* goes away. (The references will be held on the "proxy" side, while
* the Layer exists on the "native" side.)
*
* The Layer has a reference to an instance of SurfaceFlinger's variant
* of GLConsumer, which holds a reference to the BufferQueue. The
* getSurfaceTexture() call returns a Binder interface reference for
* the producer interface of the buffer queue associated with the Layer.
*/
class BSurface : public BnSurface, public LayerCleaner {
wp<const Layer> mOwner;
virtual sp<IGraphicBufferProducer> getSurfaceTexture() const {
sp<IGraphicBufferProducer> res;
sp<const Layer> that( mOwner.promote() );
if (that != NULL) {
res = that->mSurfaceFlingerConsumer->getBufferQueue();
}
return res;
}
public:
BSurface(const sp<SurfaceFlinger>& flinger,
const sp<Layer>& layer)
: LayerCleaner(flinger, layer), mOwner(layer) { }
};
sp<ISurface> sur(new BSurface(mFlinger, this));
return sur;
}
wp<IBinder> Layer::getSurfaceTextureBinder() const {
return mSurfaceFlingerConsumer->getBufferQueue()->asBinder();
}
sp<ISurface> Layer::getSurface()
{
sp<ISurface> s;
Mutex::Autolock _l(mLock);
LOG_ALWAYS_FATAL_IF(mHasSurface,
"Layer::getSurface() has already been called");
mHasSurface = true;
s = createSurface();
return s;
}
// ---------------------------------------------------------------------------
// h/w composer set-up
// ---------------------------------------------------------------------------
Rect Layer::getContentCrop() const {
// this is the crop rectangle that applies to the buffer
// itself (as opposed to the window)
@ -220,11 +285,85 @@ uint32_t Layer::getContentTransform() const {
return mCurrentTransform;
}
Rect Layer::computeBounds() const {
const Layer::State& s(drawingState());
Rect win(s.active.w, s.active.h);
if (!s.active.crop.isEmpty()) {
win.intersect(s.active.crop, &win);
}
return win;
}
Rect Layer::computeCrop(const sp<const DisplayDevice>& hw) const {
/*
* The way we compute the crop (aka. texture coordinates when we have a
* Layer) produces a different output from the GL code in
* drawWithOpenGL() due to HWC being limited to integers. The difference
* can be large if getContentTransform() contains a large scale factor.
* See comments in drawWithOpenGL() for more details.
*/
// the content crop is the area of the content that gets scaled to the
// layer's size.
Rect crop(getContentCrop());
// the active.crop is the area of the window that gets cropped, but not
// scaled in any ways.
const State& s(drawingState());
// apply the projection's clipping to the window crop in
// layerstack space, and convert-back to layer space.
// if there are no window scaling (or content scaling) involved,
// this operation will map to full pixels in the buffer.
// NOTE: should we revert to GL composition if a scaling is involved
// since it cannot be represented in the HWC API?
Rect activeCrop(s.transform.transform(s.active.crop));
activeCrop.intersect(hw->getViewport(), &activeCrop);
activeCrop = s.transform.inverse().transform(activeCrop);
// paranoia: make sure the window-crop is constrained in the
// window's bounds
activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop);
if (!activeCrop.isEmpty()) {
// Transform the window crop to match the buffer coordinate system,
// which means using the inverse of the current transform set on the
// SurfaceFlingerConsumer.
uint32_t invTransform = getContentTransform();
int winWidth = s.active.w;
int winHeight = s.active.h;
if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
NATIVE_WINDOW_TRANSFORM_FLIP_H;
winWidth = s.active.h;
winHeight = s.active.w;
}
const Rect winCrop = activeCrop.transform(
invTransform, s.active.w, s.active.h);
// the code below essentially performs a scaled intersection
// of crop and winCrop
float xScale = float(crop.width()) / float(winWidth);
float yScale = float(crop.height()) / float(winHeight);
int insetL = int(ceilf( winCrop.left * xScale));
int insetT = int(ceilf( winCrop.top * yScale));
int insetR = int(ceilf((winWidth - winCrop.right ) * xScale));
int insetB = int(ceilf((winHeight - winCrop.bottom) * yScale));
crop.left += insetL;
crop.top += insetT;
crop.right -= insetR;
crop.bottom -= insetB;
}
return crop;
}
void Layer::setGeometry(
const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer)
{
LayerBase::setGeometry(hw, layer);
layer.setDefaultState();
// enable this layer
layer.setSkip(false);
@ -233,7 +372,21 @@ void Layer::setGeometry(
layer.setSkip(true);
}
// this gives us only the "orientation" component of the transform
const State& s(drawingState());
if (!isOpaque() || s.alpha != 0xFF) {
layer.setBlending(mPremultipliedAlpha ?
HWC_BLENDING_PREMULT :
HWC_BLENDING_COVERAGE);
}
// apply the layer's transform, followed by the display's global transform
// here we're guaranteed that the layer's transform preserves rects
Rect frame(s.transform.transform(computeBounds()));
frame.intersect(hw->getViewport(), &frame);
const Transform& tr(hw->getTransform());
layer.setFrame(tr.transform(frame));
layer.setCrop(computeCrop(hw));
layer.setPlaneAlpha(s.alpha);
/*
@ -245,22 +398,29 @@ void Layer::setGeometry(
*/
const Transform bufferOrientation(mCurrentTransform);
const Transform tr(hw->getTransform() * s.transform * bufferOrientation);
const Transform transform(tr * s.transform * bufferOrientation);
// this gives us only the "orientation" component of the transform
const uint32_t finalTransform = tr.getOrientation();
// we can only handle simple transformation
if (finalTransform & Transform::ROT_INVALID) {
const uint32_t orientation = transform.getOrientation();
if (orientation & Transform::ROT_INVALID) {
// we can only handle simple transformation
layer.setSkip(true);
} else {
layer.setTransform(finalTransform);
layer.setTransform(orientation);
}
}
void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer) {
LayerBase::setPerFrameData(hw, layer);
// we have to set the visible region on every frame because
// we currently free it during onLayerDisplayed(), which is called
// after HWComposer::commit() -- every frame.
// Apply this display's projection's viewport to the visible region
// before giving it to the HWC HAL.
const Transform& tr = hw->getTransform();
Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
layer.setVisibleRegionScreen(visible);
// NOTE: buffer can be NULL if the client never drew into this
// layer yet, or if we ran out of memory
layer.setBuffer(mActiveBuffer);
@ -285,6 +445,18 @@ void Layer::setAcquireFence(const sp<const DisplayDevice>& hw,
layer.setAcquireFenceFd(fenceFd);
}
// ---------------------------------------------------------------------------
// drawing...
// ---------------------------------------------------------------------------
void Layer::draw(const sp<const DisplayDevice>& hw, const Region& clip) const {
onDraw(hw, clip);
}
void Layer::draw(const sp<const DisplayDevice>& hw) {
onDraw( hw, Region(hw->bounds()) );
}
void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const
{
ATRACE_CALL();
@ -304,8 +476,8 @@ void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const
mFlinger->mDrawingState.layersSortedByZ);
const size_t count = drawingLayers.size();
for (size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer(drawingLayers[i]);
if (layer.get() == static_cast<LayerBase const*>(this))
const sp<Layer>& layer(drawingLayers[i]);
if (layer.get() == static_cast<Layer const*>(this))
break;
under.orSelf( hw->getTransform().transform(layer->visibleRegion) );
}
@ -365,6 +537,119 @@ void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const
glDisable(GL_TEXTURE_2D);
}
void Layer::clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) const
{
const uint32_t fbHeight = hw->getHeight();
glColor4f(red,green,blue,alpha);
glDisable(GL_TEXTURE_EXTERNAL_OES);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
LayerMesh mesh;
computeGeometry(hw, &mesh);
glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
}
void Layer::clearWithOpenGL(
const sp<const DisplayDevice>& hw, const Region& clip) const {
clearWithOpenGL(hw, clip, 0,0,0,0);
}
void Layer::drawWithOpenGL(
const sp<const DisplayDevice>& hw, const Region& clip) const {
const uint32_t fbHeight = hw->getHeight();
const State& s(drawingState());
GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
if (CC_UNLIKELY(s.alpha < 0xFF)) {
const GLfloat alpha = s.alpha * (1.0f/255.0f);
if (mPremultipliedAlpha) {
glColor4f(alpha, alpha, alpha, alpha);
} else {
glColor4f(1, 1, 1, alpha);
}
glEnable(GL_BLEND);
glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
} else {
glColor4f(1, 1, 1, 1);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
if (!isOpaque()) {
glEnable(GL_BLEND);
glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
} else {
glDisable(GL_BLEND);
}
}
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;
};
/*
* NOTE: the way we compute the texture coordinates here produces
* different results than when we take the HWC path -- in the later case
* the "source crop" is rounded to texel boundaries.
* This can produce significantly different results when the texture
* is scaled by a large amount.
*
* The GL code below is more logical (imho), and the difference with
* HWC is due to a limitation of the HWC API to integers -- a question
* is suspend is wether we should ignore this problem or revert to
* GL composition when a buffer scaling is applied (maybe with some
* minimal value)? Or, we could make GL behave like HWC -- but this feel
* like more of a hack.
*/
const Rect win(computeBounds());
GLfloat left = GLfloat(win.left) / GLfloat(s.active.w);
GLfloat top = GLfloat(win.top) / GLfloat(s.active.h);
GLfloat right = GLfloat(win.right) / GLfloat(s.active.w);
GLfloat bottom = GLfloat(win.bottom) / GLfloat(s.active.h);
TexCoords texCoords[4];
texCoords[0].u = left;
texCoords[0].v = top;
texCoords[1].u = left;
texCoords[1].v = bottom;
texCoords[2].u = right;
texCoords[2].v = bottom;
texCoords[3].u = right;
texCoords[3].v = top;
for (int i = 0; i < 4; i++) {
texCoords[i].v = 1.0f - texCoords[i].v;
}
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_BLEND);
}
void Layer::setFiltering(bool filtering) {
mFiltering = filtering;
}
bool Layer::getFiltering() const {
return mFiltering;
}
// As documented in libhardware header, formats in the range
// 0x100 - 0x1FF are specific to the HAL implementation, and
// are known to have no alpha channel
@ -383,6 +668,29 @@ bool Layer::getOpacityForFormat(uint32_t format)
return (err || info.h_alpha <= info.l_alpha);
}
// ----------------------------------------------------------------------------
// local state
// ----------------------------------------------------------------------------
void Layer::computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const
{
const Layer::State& s(drawingState());
const Transform tr(hw->getTransform() * s.transform);
const uint32_t hw_h = hw->getHeight();
Rect win(s.active.w, s.active.h);
if (!s.active.crop.isEmpty()) {
win.intersect(s.active.crop, &win);
}
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];
}
}
}
bool Layer::isOpaque() const
{
@ -404,8 +712,39 @@ bool Layer::isProtected() const
(activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
}
uint32_t Layer::doTransaction(uint32_t flags)
{
bool Layer::isFixedSize() const {
return mCurrentScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
}
bool Layer::isCropped() const {
return !mCurrentCrop.isEmpty();
}
bool Layer::needsFiltering(const sp<const DisplayDevice>& hw) const {
return mNeedsFiltering || hw->needsFiltering();
}
void Layer::setVisibleRegion(const Region& visibleRegion) {
// always called from main thread
this->visibleRegion = visibleRegion;
}
void Layer::setCoveredRegion(const Region& coveredRegion) {
// always called from main thread
this->coveredRegion = coveredRegion;
}
void Layer::setVisibleNonTransparentRegion(const Region&
setVisibleNonTransparentRegion) {
// always called from main thread
this->visibleNonTransparentRegion = setVisibleNonTransparentRegion;
}
// ----------------------------------------------------------------------------
// transaction
// ----------------------------------------------------------------------------
uint32_t Layer::doTransaction(uint32_t flags) {
ATRACE_CALL();
const Layer::State& front(drawingState());
@ -464,7 +803,7 @@ uint32_t Layer::doTransaction(uint32_t flags)
(temp.requested.h != temp.active.h);
if (resizePending) {
// don't let LayerBase::doTransaction update the drawing state
// don't let Layer::doTransaction update the drawing state
// if we have a pending resize, unless we are in fixed-size mode.
// the drawing state will be updated only once we receive a buffer
// with the correct size.
@ -477,15 +816,117 @@ uint32_t Layer::doTransaction(uint32_t flags)
}
}
return LayerBase::doTransaction(flags);
// always set active to requested, unless we're asked not to
// this is used by Layer, which special cases resizes.
if (flags & eDontUpdateGeometryState) {
} else {
Layer::State& editTemp(currentState());
editTemp.active = temp.requested;
}
if (front.active != temp.active) {
// invalidate and recompute the visible regions if needed
flags |= Layer::eVisibleRegion;
}
if (temp.sequence != front.sequence) {
// invalidate and recompute the visible regions if needed
flags |= eVisibleRegion;
this->contentDirty = true;
// we may use linear filtering, if the matrix scales us
const uint8_t type = temp.transform.getType();
mNeedsFiltering = (!temp.transform.preserveRects() ||
(type >= Transform::SCALE));
}
// Commit the transaction
commitTransaction();
return flags;
}
bool Layer::isFixedSize() const {
return mCurrentScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
void Layer::commitTransaction() {
mDrawingState = mCurrentState;
}
bool Layer::isCropped() const {
return !mCurrentCrop.isEmpty();
uint32_t Layer::getTransactionFlags(uint32_t flags) {
return android_atomic_and(~flags, &mTransactionFlags) & flags;
}
uint32_t Layer::setTransactionFlags(uint32_t flags) {
return android_atomic_or(flags, &mTransactionFlags);
}
bool Layer::setPosition(float x, float y) {
if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
return false;
mCurrentState.sequence++;
mCurrentState.transform.set(x, y);
setTransactionFlags(eTransactionNeeded);
return true;
}
bool Layer::setLayer(uint32_t z) {
if (mCurrentState.z == z)
return false;
mCurrentState.sequence++;
mCurrentState.z = z;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool Layer::setSize(uint32_t w, uint32_t h) {
if (mCurrentState.requested.w == w && mCurrentState.requested.h == h)
return false;
mCurrentState.requested.w = w;
mCurrentState.requested.h = h;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool Layer::setAlpha(uint8_t alpha) {
if (mCurrentState.alpha == alpha)
return false;
mCurrentState.sequence++;
mCurrentState.alpha = alpha;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
mCurrentState.sequence++;
mCurrentState.transform.set(
matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
setTransactionFlags(eTransactionNeeded);
return true;
}
bool Layer::setTransparentRegionHint(const Region& transparent) {
mCurrentState.sequence++;
mCurrentState.transparentRegion = transparent;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool Layer::setFlags(uint8_t flags, uint8_t mask) {
const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
if (mCurrentState.flags == newFlags)
return false;
mCurrentState.sequence++;
mCurrentState.flags = newFlags;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool Layer::setCrop(const Rect& crop) {
if (mCurrentState.requested.crop == crop)
return false;
mCurrentState.sequence++;
mCurrentState.requested.crop = crop;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool Layer::setLayerStack(uint32_t layerStack) {
if (mCurrentState.layerStack == layerStack)
return false;
mCurrentState.sequence++;
mCurrentState.layerStack = layerStack;
setTransactionFlags(eTransactionNeeded);
return true;
}
// ----------------------------------------------------------------------------
@ -528,7 +969,9 @@ void Layer::onPostComposition() {
}
bool Layer::isVisible() const {
return LayerBase::isVisible() && (mActiveBuffer != NULL);
const Layer::State& s(mDrawingState);
return !(s.flags & layer_state_t::eLayerHidden) && s.alpha
&& (mActiveBuffer != NULL);
}
Region Layer::latchBuffer(bool& recomputeVisibleRegions)
@ -702,44 +1145,6 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
return outDirtyRegion;
}
void Layer::dump(String8& result, char* buffer, size_t SIZE) const
{
LayerBase::dump(result, buffer, SIZE);
sp<const GraphicBuffer> buf0(mActiveBuffer);
uint32_t w0=0, h0=0, s0=0, f0=0;
if (buf0 != 0) {
w0 = buf0->getWidth();
h0 = buf0->getHeight();
s0 = buf0->getStride();
f0 = buf0->format;
}
snprintf(buffer, SIZE,
" "
"format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
" queued-frames=%d, mRefreshPending=%d\n",
mFormat, w0, h0, s0,f0,
mQueuedFrames, mRefreshPending);
result.append(buffer);
if (mSurfaceFlingerConsumer != 0) {
mSurfaceFlingerConsumer->dump(result, " ", buffer, SIZE);
}
}
void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const
{
LayerBase::dumpStats(result, buffer, SIZE);
mFrameTracker.dump(result);
}
void Layer::clearStats()
{
LayerBase::clearStats();
mFrameTracker.clear();
}
uint32_t Layer::getEffectiveUsage(uint32_t usage) const
{
// TODO: should we do something special if mSecure is set?
@ -766,6 +1171,86 @@ void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const {
mSurfaceFlingerConsumer->setTransformHint(orientation);
}
// ----------------------------------------------------------------------------
// debugging
// ----------------------------------------------------------------------------
void Layer::dump(String8& result, char* buffer, size_t SIZE) const
{
const Layer::State& s(drawingState());
snprintf(buffer, SIZE,
"+ %s %p (%s)\n",
getTypeId(), this, getName().string());
result.append(buffer);
s.transparentRegion.dump(result, "transparentRegion");
visibleRegion.dump(result, "visibleRegion");
sp<Client> client(mClientRef.promote());
snprintf(buffer, SIZE,
" "
"layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
"isOpaque=%1d, invalidate=%1d, "
"alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
" client=%p\n",
s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
s.active.crop.left, s.active.crop.top,
s.active.crop.right, s.active.crop.bottom,
isOpaque(), contentDirty,
s.alpha, s.flags,
s.transform[0][0], s.transform[0][1],
s.transform[1][0], s.transform[1][1],
client.get());
result.append(buffer);
sp<const GraphicBuffer> buf0(mActiveBuffer);
uint32_t w0=0, h0=0, s0=0, f0=0;
if (buf0 != 0) {
w0 = buf0->getWidth();
h0 = buf0->getHeight();
s0 = buf0->getStride();
f0 = buf0->format;
}
snprintf(buffer, SIZE,
" "
"format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
" queued-frames=%d, mRefreshPending=%d\n",
mFormat, w0, h0, s0,f0,
mQueuedFrames, mRefreshPending);
result.append(buffer);
if (mSurfaceFlingerConsumer != 0) {
mSurfaceFlingerConsumer->dump(result, " ", buffer, SIZE);
}
}
void Layer::shortDump(String8& result, char* scratch, size_t size) const {
Layer::dump(result, scratch, size);
}
void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const {
mFrameTracker.dump(result);
}
void Layer::clearStats() {
mFrameTracker.clear();
}
// ---------------------------------------------------------------------------
Layer::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
const sp<Layer>& layer)
: mFlinger(flinger), mLayer(layer) {
}
Layer::LayerCleaner::~LayerCleaner() {
// destroy client resources
mFlinger->onLayerDestroyed(mLayer);
}
// ---------------------------------------------------------------------------

View File

@ -20,118 +20,356 @@
#include <stdint.h>
#include <sys/types.h>
#include <utils/Timers.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
#include <gui/ISurfaceComposerClient.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
#include "SurfaceFlingerConsumer.h"
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/Timers.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
#include <ui/Region.h>
#include <gui/ISurfaceComposerClient.h>
#include <private/gui/LayerState.h>
#include "FrameTracker.h"
#include "LayerBase.h"
#include "Client.h"
#include "SurfaceFlinger.h"
#include "SurfaceFlingerConsumer.h"
#include "SurfaceTextureLayer.h"
#include "Transform.h"
#include "DisplayHardware/HWComposer.h"
namespace android {
// ---------------------------------------------------------------------------
class Client;
class DisplayDevice;
class GraphicBuffer;
class SurfaceFlinger;
class GLExtensions;
// ---------------------------------------------------------------------------
/*
* The Layer class is essentially a LayerBase combined with a BufferQueue.
* A new BufferQueue and a new SurfaceFlingerConsumer are created when the
* Layer is first referenced.
*
* This also implements onFrameAvailable(), which notifies SurfaceFlinger
* that new data has arrived.
*/
class Layer : public LayerBase,
public SurfaceFlingerConsumer::FrameAvailableListener
{
class Layer : public SurfaceFlingerConsumer::FrameAvailableListener {
static int32_t sSequence;
public:
mutable bool contentDirty;
// regions below are in window-manager space
Region visibleRegion;
Region coveredRegion;
Region visibleNonTransparentRegion;
int32_t sequence;
enum { // flags for doTransaction()
eDontUpdateGeometryState = 0x00000001,
eVisibleRegion = 0x00000002,
};
struct Geometry {
uint32_t w;
uint32_t h;
Rect crop;
inline bool operator ==(const Geometry& rhs) const {
return (w == rhs.w && h == rhs.h && crop == rhs.crop);
}
inline bool operator !=(const Geometry& rhs) const {
return !operator ==(rhs);
}
};
struct State {
Geometry active;
Geometry requested;
uint32_t z;
uint32_t layerStack;
uint8_t alpha;
uint8_t flags;
uint8_t reserved[2];
int32_t sequence; // changes when visible regions can change
Transform transform;
Region transparentRegion;
};
class LayerMesh {
friend class Layer;
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;
}
};
// -----------------------------------------------------------------------
Layer(SurfaceFlinger* flinger, const sp<Client>& client);
virtual ~Layer();
virtual const char* getTypeId() const { return "Layer"; }
// the this layer's size and format
status_t setBuffers(uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags=0);
virtual bool isFixedSize() const;
// Creates an ISurface associated with this object. This may only be
// called once. to provide your own ISurface, override createSurface().
sp<ISurface> getSurface();
// modify current state
bool setPosition(float x, float y);
bool setLayer(uint32_t z);
bool setSize(uint32_t w, uint32_t h);
bool setAlpha(uint8_t alpha);
bool setMatrix(const layer_state_t::matrix22_t& matrix);
bool setTransparentRegionHint(const Region& transparent);
bool setFlags(uint8_t flags, uint8_t mask);
bool setCrop(const Rect& crop);
bool setLayerStack(uint32_t layerStack);
void commitTransaction();
uint32_t getTransactionFlags(uint32_t flags);
uint32_t setTransactionFlags(uint32_t flags);
void computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const;
Rect computeBounds() const;
// -----------------------------------------------------------------------
/*
* initStates - called just after construction
*/
virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
virtual const char* getTypeId() const { return "Layer"; }
virtual void setName(const String8& name);
String8 getName() const;
// LayerBase interface
virtual void setGeometry(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer);
virtual void setPerFrameData(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer);
virtual void setAcquireFence(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer);
/*
* called after page-flip
*/
virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface* layer);
/*
* called before composition.
* returns true if the layer has pending updates.
*/
virtual bool onPreComposition();
/*
* called after composition.
*/
virtual void onPostComposition();
/*
* draw - performs some global clipping optimizations
* and calls onDraw().
* Typically this method is not overridden, instead implement onDraw()
* to perform the actual drawing.
*/
virtual void draw(const sp<const DisplayDevice>& hw, const Region& clip) const;
virtual void draw(const sp<const DisplayDevice>& hw);
/*
* onDraw - draws the surface.
*/
virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const;
/*
* needsLinearFiltering - true if this surface's state requires filtering
*/
virtual bool needsFiltering(const sp<const DisplayDevice>& hw) const;
/*
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
*/
virtual uint32_t doTransaction(uint32_t transactionFlags);
/*
* setVisibleRegion - called to set the new visible region. This gives
* a chance to update the new visible region or record the fact it changed.
*/
virtual void setVisibleRegion(const Region& visibleRegion);
/*
* setCoveredRegion - called when the covered region changes. The covered
* region corresponds to any area of the surface that is covered
* (transparently or not) by another surface.
*/
virtual void setCoveredRegion(const Region& coveredRegion);
/*
* setVisibleNonTransparentRegion - called when the visible and
* non-transparent region changes.
*/
virtual void setVisibleNonTransparentRegion(const Region&
visibleNonTransparentRegion);
/*
* 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 Region latchBuffer(bool& recomputeVisibleRegions);
/*
* isOpaque - true if this surface is opaque
*/
virtual bool isOpaque() const;
/*
* isSecure - true if this surface is secure, that is if it prevents
* screenshots or VNC servers.
*/
virtual bool isSecure() const { return mSecure; }
/*
* isProtected - true if the layer may contain protected content in the
* GRALLOC_USAGE_PROTECTED sense.
*/
virtual bool isProtected() const;
virtual void onRemoved();
virtual sp<Layer> getLayer() const { return const_cast<Layer*>(this); }
virtual void setName(const String8& name);
/*
* isVisible - true if this layer is visible, false otherwise
*/
virtual bool isVisible() const;
// LayerBase interface
virtual wp<IBinder> getSurfaceTextureBinder() const;
/*
* isFixedSize - true if content has a fixed size
*/
virtual bool isFixedSize() const;
// only for debugging
inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
/*
* called with the state lock when the surface is removed from the
* current list
*/
virtual void onRemoved();
virtual wp<IBinder> getSurfaceTextureBinder() const;
// Updates the transform hint in our SurfaceFlingerConsumer to match
// the current orientation of the display device.
virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const;
/*
* returns the rectangle that crops the content of the layer and scales it
* to the layer's size.
*/
virtual Rect getContentCrop() const;
/*
* returns the transform bits (90 rotation / h-flip / v-flip) of the
* layer's content
*/
virtual uint32_t getContentTransform() const;
protected:
virtual void onFirstRef();
// -----------------------------------------------------------------------
void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const;
void setFiltering(bool filtering);
bool getFiltering() const;
// only for debugging
inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
inline const State& drawingState() const { return mDrawingState; }
inline const State& currentState() const { return mCurrentState; }
inline State& currentState() { return mCurrentState; }
/* always call base class first */
virtual void dump(String8& result, char* scratch, size_t size) const;
virtual void shortDump(String8& result, char* scratch, size_t size) const;
virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const;
virtual void clearStats();
sp<SurfaceFlingerConsumer> getConsumer() const {
return mSurfaceFlingerConsumer;
}
protected:
// constant
sp<SurfaceFlinger> mFlinger;
virtual void onFirstRef();
/*
* Trivial class, used to ensure that mFlinger->onLayerDestroyed(mLayer)
* is called.
*/
class LayerCleaner {
sp<SurfaceFlinger> mFlinger;
wp<Layer> mLayer;
protected:
~LayerCleaner();
public:
LayerCleaner(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer);
};
private:
// Creates an instance of ISurface for this Layer.
virtual sp<ISurface> createSurface();
// Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener
virtual void onFrameAvailable();
uint32_t getEffectiveUsage(uint32_t usage) const;
Rect computeCrop(const sp<const DisplayDevice>& hw) const;
bool isCropped() const;
static bool getOpacityForFormat(uint32_t format);
// Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener
virtual void onFrameAvailable();
// drawing
void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
GLclampf r, GLclampf g, GLclampf b, GLclampf alpha) const;
void drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const;
// -----------------------------------------------------------------------
// constants
sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer;
GLuint mTextureName;
bool mPremultipliedAlpha;
String8 mName;
mutable bool mDebug;
PixelFormat mFormat;
const GLExtensions& mGLExtensions;
bool mOpaqueLayer;
// these are protected by an external lock
State mCurrentState;
State mDrawingState;
volatile int32_t mTransactionFlags;
// thread-safe
volatile int32_t mQueuedFrames;
@ -145,15 +383,20 @@ private:
bool mCurrentOpacity;
bool mRefreshPending;
bool mFrameLatencyNeeded;
// constants
PixelFormat mFormat;
const GLExtensions& mGLExtensions;
bool mOpaqueLayer;
// Whether filtering is forced on or not
bool mFiltering;
// Whether filtering is needed b/c of the drawingstate
bool mNeedsFiltering;
// page-flip thread (currently main thread)
bool mSecure; // no screenshots
bool mSecure; // no screenshots
bool mProtectedByApp; // application requires protected path to external sink
// protected by mLock
mutable Mutex mLock;
// Set to true if an ISurface has been associated with this object.
mutable bool mHasSurface;
const wp<Client> mClientRef;
};
// ---------------------------------------------------------------------------

View File

@ -1,635 +0,0 @@
/*
* Copyright (C) 2007 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 <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <math.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <hardware/hardware.h>
#include "clz.h"
#include "Client.h"
#include "LayerBase.h"
#include "Layer.h"
#include "SurfaceFlinger.h"
#include "DisplayDevice.h"
namespace android {
// ---------------------------------------------------------------------------
int32_t LayerBase::sSequence = 1;
LayerBase::LayerBase(SurfaceFlinger* flinger, const sp<Client>& client)
: contentDirty(false),
sequence(uint32_t(android_atomic_inc(&sSequence))),
mFlinger(flinger), mFiltering(false),
mNeedsFiltering(false),
mTransactionFlags(0),
mPremultipliedAlpha(true), mName("unnamed"), mDebug(false),
mHasSurface(false),
mClientRef(client)
{
}
LayerBase::~LayerBase()
{
sp<Client> c(mClientRef.promote());
if (c != 0) {
c->detachLayer(this);
}
}
void LayerBase::setName(const String8& name) {
mName = name;
}
String8 LayerBase::getName() const {
return mName;
}
void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags)
{
uint32_t layerFlags = 0;
if (flags & ISurfaceComposerClient::eHidden)
layerFlags = layer_state_t::eLayerHidden;
if (flags & ISurfaceComposerClient::eNonPremultiplied)
mPremultipliedAlpha = false;
mCurrentState.active.w = w;
mCurrentState.active.h = h;
mCurrentState.active.crop.makeInvalid();
mCurrentState.z = 0;
mCurrentState.alpha = 0xFF;
mCurrentState.layerStack = 0;
mCurrentState.flags = layerFlags;
mCurrentState.sequence = 0;
mCurrentState.transform.set(0, 0);
mCurrentState.requested = mCurrentState.active;
// drawing state & current state are identical
mDrawingState = mCurrentState;
}
bool LayerBase::needsFiltering(const sp<const DisplayDevice>& hw) const {
return mNeedsFiltering || hw->needsFiltering();
}
void LayerBase::commitTransaction() {
mDrawingState = mCurrentState;
}
void LayerBase::forceVisibilityTransaction() {
// this can be called without SurfaceFlinger.mStateLock, but if we
// can atomically increment the sequence number, it doesn't matter.
android_atomic_inc(&mCurrentState.sequence);
requestTransaction();
}
bool LayerBase::requestTransaction() {
int32_t old = setTransactionFlags(eTransactionNeeded);
return ((old & eTransactionNeeded) == 0);
}
uint32_t LayerBase::getTransactionFlags(uint32_t flags) {
return android_atomic_and(~flags, &mTransactionFlags) & flags;
}
uint32_t LayerBase::setTransactionFlags(uint32_t flags) {
return android_atomic_or(flags, &mTransactionFlags);
}
bool LayerBase::setPosition(float x, float y) {
if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y)
return false;
mCurrentState.sequence++;
mCurrentState.transform.set(x, y);
requestTransaction();
return true;
}
bool LayerBase::setLayer(uint32_t z) {
if (mCurrentState.z == z)
return false;
mCurrentState.sequence++;
mCurrentState.z = z;
requestTransaction();
return true;
}
bool LayerBase::setSize(uint32_t w, uint32_t h) {
if (mCurrentState.requested.w == w && mCurrentState.requested.h == h)
return false;
mCurrentState.requested.w = w;
mCurrentState.requested.h = h;
requestTransaction();
return true;
}
bool LayerBase::setAlpha(uint8_t alpha) {
if (mCurrentState.alpha == alpha)
return false;
mCurrentState.sequence++;
mCurrentState.alpha = alpha;
requestTransaction();
return true;
}
bool LayerBase::setMatrix(const layer_state_t::matrix22_t& matrix) {
mCurrentState.sequence++;
mCurrentState.transform.set(
matrix.dsdx, matrix.dsdy, matrix.dtdx, matrix.dtdy);
requestTransaction();
return true;
}
bool LayerBase::setTransparentRegionHint(const Region& transparent) {
mCurrentState.sequence++;
mCurrentState.transparentRegion = transparent;
requestTransaction();
return true;
}
bool LayerBase::setFlags(uint8_t flags, uint8_t mask) {
const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
if (mCurrentState.flags == newFlags)
return false;
mCurrentState.sequence++;
mCurrentState.flags = newFlags;
requestTransaction();
return true;
}
bool LayerBase::setCrop(const Rect& crop) {
if (mCurrentState.requested.crop == crop)
return false;
mCurrentState.sequence++;
mCurrentState.requested.crop = crop;
requestTransaction();
return true;
}
bool LayerBase::setLayerStack(uint32_t layerStack) {
if (mCurrentState.layerStack == layerStack)
return false;
mCurrentState.sequence++;
mCurrentState.layerStack = layerStack;
requestTransaction();
return true;
}
void LayerBase::setVisibleRegion(const Region& visibleRegion) {
// always called from main thread
this->visibleRegion = visibleRegion;
}
void LayerBase::setCoveredRegion(const Region& coveredRegion) {
// always called from main thread
this->coveredRegion = coveredRegion;
}
void LayerBase::setVisibleNonTransparentRegion(const Region&
setVisibleNonTransparentRegion) {
// always called from main thread
this->visibleNonTransparentRegion = setVisibleNonTransparentRegion;
}
uint32_t LayerBase::doTransaction(uint32_t flags)
{
const Layer::State& front(drawingState());
const Layer::State& temp(currentState());
// always set active to requested, unless we're asked not to
// this is used by Layer, which special cases resizes.
if (flags & eDontUpdateGeometryState) {
} else {
Layer::State& editTemp(currentState());
editTemp.active = temp.requested;
}
if (front.active != temp.active) {
// invalidate and recompute the visible regions if needed
flags |= Layer::eVisibleRegion;
}
if (temp.sequence != front.sequence) {
// invalidate and recompute the visible regions if needed
flags |= eVisibleRegion;
this->contentDirty = true;
// we may use linear filtering, if the matrix scales us
const uint8_t type = temp.transform.getType();
mNeedsFiltering = (!temp.transform.preserveRects() ||
(type >= Transform::SCALE));
}
// Commit the transaction
commitTransaction();
return flags;
}
void LayerBase::computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const
{
const Layer::State& s(drawingState());
const Transform tr(hw->getTransform() * s.transform);
const uint32_t hw_h = hw->getHeight();
Rect win(s.active.w, s.active.h);
if (!s.active.crop.isEmpty()) {
win.intersect(s.active.crop, &win);
}
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];
}
}
}
Rect LayerBase::computeBounds() const {
const Layer::State& s(drawingState());
Rect win(s.active.w, s.active.h);
if (!s.active.crop.isEmpty()) {
win.intersect(s.active.crop, &win);
}
return win;
}
Region LayerBase::latchBuffer(bool& recomputeVisibleRegions) {
Region result;
return result;
}
Rect LayerBase::getContentCrop() const {
// regular layers just use their active area as the content crop
const State& s(drawingState());
return Rect(s.active.w, s.active.h);
}
uint32_t LayerBase::getContentTransform() const {
// regular layers don't have a content transform
return 0;
}
Rect LayerBase::computeCrop(const sp<const DisplayDevice>& hw) const {
/*
* The way we compute the crop (aka. texture coordinates when we have a
* Layer) produces a different output from the GL code in
* drawWithOpenGL() due to HWC being limited to integers. The difference
* can be large if getContentTransform() contains a large scale factor.
* See comments in drawWithOpenGL() for more details.
*/
// the content crop is the area of the content that gets scaled to the
// layer's size.
Rect crop(getContentCrop());
// the active.crop is the area of the window that gets cropped, but not
// scaled in any ways.
const State& s(drawingState());
// apply the projection's clipping to the window crop in
// layerstack space, and convert-back to layer space.
// if there are no window scaling (or content scaling) involved,
// this operation will map to full pixels in the buffer.
// NOTE: should we revert to GL composition if a scaling is involved
// since it cannot be represented in the HWC API?
Rect activeCrop(s.transform.transform(s.active.crop));
activeCrop.intersect(hw->getViewport(), &activeCrop);
activeCrop = s.transform.inverse().transform(activeCrop);
// paranoia: make sure the window-crop is constrained in the
// window's bounds
activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop);
if (!activeCrop.isEmpty()) {
// Transform the window crop to match the buffer coordinate system,
// which means using the inverse of the current transform set on the
// SurfaceFlingerConsumer.
uint32_t invTransform = getContentTransform();
int winWidth = s.active.w;
int winHeight = s.active.h;
if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
NATIVE_WINDOW_TRANSFORM_FLIP_H;
winWidth = s.active.h;
winHeight = s.active.w;
}
const Rect winCrop = activeCrop.transform(
invTransform, s.active.w, s.active.h);
// the code below essentially performs a scaled intersection
// of crop and winCrop
float xScale = float(crop.width()) / float(winWidth);
float yScale = float(crop.height()) / float(winHeight);
int insetL = int(ceilf( winCrop.left * xScale));
int insetT = int(ceilf( winCrop.top * yScale));
int insetR = int(ceilf((winWidth - winCrop.right ) * xScale));
int insetB = int(ceilf((winHeight - winCrop.bottom) * yScale));
crop.left += insetL;
crop.top += insetT;
crop.right -= insetR;
crop.bottom -= insetB;
}
return crop;
}
void LayerBase::setGeometry(
const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer)
{
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) {
layer.setTransform(0);
} else {
layer.setTransform(finalTransform);
}
if (!isOpaque() || s.alpha != 0xFF) {
layer.setBlending(mPremultipliedAlpha ?
HWC_BLENDING_PREMULT :
HWC_BLENDING_COVERAGE);
}
// apply the layer's transform, followed by the display's global transform
// here we're guaranteed that the layer's transform preserves rects
Rect frame(s.transform.transform(computeBounds()));
frame.intersect(hw->getViewport(), &frame);
const Transform& tr(hw->getTransform());
layer.setFrame(tr.transform(frame));
layer.setCrop(computeCrop(hw));
}
void LayerBase::setPerFrameData(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer) {
// we have to set the visible region on every frame because
// we currently free it during onLayerDisplayed(), which is called
// after HWComposer::commit() -- every frame.
// Apply this display's projection's viewport to the visible region
// before giving it to the HWC HAL.
const Transform& tr = hw->getTransform();
Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
layer.setVisibleRegionScreen(visible);
}
void LayerBase::setAcquireFence(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer) {
layer.setAcquireFenceFd(-1);
}
void LayerBase::onLayerDisplayed(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface* layer) {
if (layer) {
layer->onDisplayed();
}
}
void LayerBase::setFiltering(bool filtering)
{
mFiltering = filtering;
}
bool LayerBase::getFiltering() const
{
return mFiltering;
}
bool LayerBase::isVisible() const {
const Layer::State& s(mDrawingState);
return !(s.flags & layer_state_t::eLayerHidden) && s.alpha;
}
void LayerBase::draw(const sp<const DisplayDevice>& hw, const Region& clip) const
{
onDraw(hw, clip);
}
void LayerBase::draw(const sp<const DisplayDevice>& hw)
{
onDraw( hw, Region(hw->bounds()) );
}
void LayerBase::clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) const
{
const uint32_t fbHeight = hw->getHeight();
glColor4f(red,green,blue,alpha);
glDisable(GL_TEXTURE_EXTERNAL_OES);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
LayerMesh mesh;
computeGeometry(hw, &mesh);
glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
}
void LayerBase::clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const
{
clearWithOpenGL(hw, clip, 0,0,0,0);
}
void LayerBase::drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const
{
const uint32_t fbHeight = hw->getHeight();
const State& s(drawingState());
GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
if (CC_UNLIKELY(s.alpha < 0xFF)) {
const GLfloat alpha = s.alpha * (1.0f/255.0f);
if (mPremultipliedAlpha) {
glColor4f(alpha, alpha, alpha, alpha);
} else {
glColor4f(1, 1, 1, alpha);
}
glEnable(GL_BLEND);
glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
} else {
glColor4f(1, 1, 1, 1);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
if (!isOpaque()) {
glEnable(GL_BLEND);
glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
} else {
glDisable(GL_BLEND);
}
}
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;
};
/*
* NOTE: the way we compute the texture coordinates here produces
* different results than when we take the HWC path -- in the later case
* the "source crop" is rounded to texel boundaries.
* This can produce significantly different results when the texture
* is scaled by a large amount.
*
* The GL code below is more logical (imho), and the difference with
* HWC is due to a limitation of the HWC API to integers -- a question
* is suspend is wether we should ignore this problem or revert to
* GL composition when a buffer scaling is applied (maybe with some
* minimal value)? Or, we could make GL behave like HWC -- but this feel
* like more of a hack.
*/
const Rect win(computeBounds());
GLfloat left = GLfloat(win.left) / GLfloat(s.active.w);
GLfloat top = GLfloat(win.top) / GLfloat(s.active.h);
GLfloat right = GLfloat(win.right) / GLfloat(s.active.w);
GLfloat bottom = GLfloat(win.bottom) / GLfloat(s.active.h);
TexCoords texCoords[4];
texCoords[0].u = left;
texCoords[0].v = top;
texCoords[1].u = left;
texCoords[1].v = bottom;
texCoords[2].u = right;
texCoords[2].v = bottom;
texCoords[3].u = right;
texCoords[3].v = top;
for (int i = 0; i < 4; i++) {
texCoords[i].v = 1.0f - texCoords[i].v;
}
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_BLEND);
}
void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
{
const Layer::State& s(drawingState());
snprintf(buffer, SIZE,
"+ %s %p (%s)\n",
getTypeId(), this, getName().string());
result.append(buffer);
s.transparentRegion.dump(result, "transparentRegion");
visibleRegion.dump(result, "visibleRegion");
sp<Client> client(mClientRef.promote());
snprintf(buffer, SIZE,
" "
"layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
"isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
"alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
" client=%p\n",
s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
s.active.crop.left, s.active.crop.top,
s.active.crop.right, s.active.crop.bottom,
isOpaque(), needsDithering(), contentDirty,
s.alpha, s.flags,
s.transform[0][0], s.transform[0][1],
s.transform[1][0], s.transform[1][1],
client.get());
result.append(buffer);
}
void LayerBase::shortDump(String8& result, char* scratch, size_t size) const {
LayerBase::dump(result, scratch, size);
}
void LayerBase::dumpStats(String8& result, char* scratch, size_t SIZE) const {
}
void LayerBase::clearStats() {
}
sp<Layer> LayerBase::getLayer() const {
return 0;
}
// ---------------------------------------------------------------------------
sp<ISurface> LayerBase::createSurface()
{
class BSurface : public BnSurface, public LayerCleaner {
virtual sp<IGraphicBufferProducer> getSurfaceTexture() const { return 0; }
public:
BSurface(const sp<SurfaceFlinger>& flinger,
const sp<LayerBase>& layer)
: LayerCleaner(flinger, layer) { }
};
sp<ISurface> sur(new BSurface(mFlinger, this));
return sur;
}
sp<ISurface> LayerBase::getSurface()
{
sp<ISurface> s;
Mutex::Autolock _l(mLock);
LOG_ALWAYS_FATAL_IF(mHasSurface,
"LayerBase::getSurface() has already been called");
mHasSurface = true;
s = createSurface();
mClientSurfaceBinder = s->asBinder();
return s;
}
wp<IBinder> LayerBase::getSurfaceBinder() const {
return mClientSurfaceBinder;
}
wp<IBinder> LayerBase::getSurfaceTextureBinder() const {
return 0;
}
// ---------------------------------------------------------------------------
LayerBase::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
const sp<LayerBase>& layer)
: mFlinger(flinger), mLayer(layer) {
}
LayerBase::LayerCleaner::~LayerCleaner() {
// destroy client resources
mFlinger->onLayerDestroyed(mLayer);
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -1,378 +0,0 @@
/*
* Copyright (C) 2007 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_LAYER_BASE_H
#define ANDROID_LAYER_BASE_H
#include <stdint.h>
#include <sys/types.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES/gl.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <ui/Region.h>
#include <gui/ISurfaceComposerClient.h>
#include <private/gui/LayerState.h>
#include "Transform.h"
#include "DisplayHardware/HWComposer.h"
namespace android {
// ---------------------------------------------------------------------------
class Client;
class DisplayDevice;
class GraphicBuffer;
class Layer;
class SurfaceFlinger;
// ---------------------------------------------------------------------------
/*
* Layers are rectangular graphic entities, internal to SurfaceFlinger.
* They have properties including width, height, Z-depth, and 2D
* transformations (chiefly translation and 90-degree rotations).
*
* Layers are organized into "layer stacks". Each layer is a member of
* exactly one layer stack, identified by an integer in Layer::State. A
* given layer stack may appear on more than one display.
*/
class LayerBase : virtual public RefBase
{
static int32_t sSequence;
public:
LayerBase(SurfaceFlinger* flinger, const sp<Client>& client);
// Creates an ISurface associated with this object. This may only be
// called once (see also getSurfaceBinder()).
sp<ISurface> getSurface();
// Returns the Binder object for the ISurface associated with
// this object.
wp<IBinder> getSurfaceBinder() const;
virtual wp<IBinder> getSurfaceTextureBinder() const;
mutable bool contentDirty;
// regions below are in window-manager space
Region visibleRegion;
Region coveredRegion;
Region visibleNonTransparentRegion;
int32_t sequence;
struct Geometry {
uint32_t w;
uint32_t h;
Rect crop;
inline bool operator == (const Geometry& rhs) const {
return (w==rhs.w && h==rhs.h && crop==rhs.crop);
}
inline bool operator != (const Geometry& rhs) const {
return !operator == (rhs);
}
};
struct State {
Geometry active;
Geometry requested;
uint32_t z;
uint32_t layerStack;
uint8_t alpha;
uint8_t flags;
uint8_t reserved[2];
int32_t sequence; // changes when visible regions can change
Transform transform;
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;
// modify current state
bool setPosition(float x, float y);
bool setLayer(uint32_t z);
bool setSize(uint32_t w, uint32_t h);
bool setAlpha(uint8_t alpha);
bool setMatrix(const layer_state_t::matrix22_t& matrix);
bool setTransparentRegionHint(const Region& transparent);
bool setFlags(uint8_t flags, uint8_t mask);
bool setCrop(const Rect& crop);
bool setLayerStack(uint32_t layerStack);
void commitTransaction();
bool requestTransaction();
void forceVisibilityTransaction();
uint32_t getTransactionFlags(uint32_t flags);
uint32_t setTransactionFlags(uint32_t flags);
void computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const;
Rect computeBounds() const;
virtual sp<Layer> getLayer() const;
virtual const char* getTypeId() const { return "LayerBase"; }
virtual void setGeometry(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer);
virtual void setPerFrameData(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer);
virtual void setAcquireFence(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer);
/**
* draw - performs some global clipping optimizations
* and calls onDraw().
* Typically this method is not overridden, instead implement onDraw()
* to perform the actual drawing.
*/
virtual void draw(const sp<const DisplayDevice>& hw, const Region& clip) const;
virtual void draw(const sp<const DisplayDevice>& hw);
/**
* onDraw - draws the surface.
*/
virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const = 0;
/**
* initStates - called just after construction
*/
virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
/**
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
*/
virtual uint32_t doTransaction(uint32_t transactionFlags);
/**
* setVisibleRegion - called to set the new visible region. This gives
* a chance to update the new visible region or record the fact it changed.
*/
virtual void setVisibleRegion(const Region& visibleRegion);
/**
* setCoveredRegion - called when the covered region changes. The covered
* region corresponds to any area of the surface that is covered
* (transparently or not) by another surface.
*/
virtual void setCoveredRegion(const Region& coveredRegion);
/**
* setVisibleNonTransparentRegion - called when the visible and
* non-transparent region changes.
*/
virtual void setVisibleNonTransparentRegion(const Region&
visibleNonTransparentRegion);
/**
* 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 Region latchBuffer(bool& recomputeVisibleRegions);
/**
* isOpaque - true if this surface is opaque
*/
virtual bool isOpaque() const { return true; }
/**
* needsDithering - true if this surface needs dithering
*/
virtual bool needsDithering() const { return false; }
/**
* needsLinearFiltering - true if this surface's state requires filtering
*/
virtual bool needsFiltering(const sp<const DisplayDevice>& hw) const;
/**
* isSecure - true if this surface is secure, that is if it prevents
* screenshots or VNC servers.
*/
virtual bool isSecure() const { return false; }
/**
* isProtected - true if the layer may contain protected content in the
* GRALLOC_USAGE_PROTECTED sense.
*/
virtual bool isProtected() const { return false; }
/*
* isVisible - true if this layer is visibile, false otherwise
*/
virtual bool isVisible() const;
/** called with the state lock when the surface is removed from the
* current list */
virtual void onRemoved() { }
/** called after page-flip
*/
virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface* layer);
/** called before composition.
* returns true if the layer has pending updates.
*/
virtual bool onPreComposition() { return false; }
/** called before composition.
*/
virtual void onPostComposition() { }
/**
* Updates the GLConsumer's transform hint, for layers that have
* a GLConsumer.
*/
virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const { }
/**
* returns the rectangle that crops the content of the layer and scales it
* to the layer's size.
*/
virtual Rect getContentCrop() const;
/*
* returns the transform bits (90 rotation / h-flip / v-flip) of the
* layer's content
*/
virtual uint32_t getContentTransform() const;
/** always call base class first */
virtual void dump(String8& result, char* scratch, size_t size) const;
virtual void shortDump(String8& result, char* scratch, size_t size) const;
virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const;
virtual void clearStats();
enum { // flags for doTransaction()
eDontUpdateGeometryState = 0x00000001,
eVisibleRegion = 0x00000002,
};
inline const State& drawingState() const { return mDrawingState; }
inline const State& currentState() const { return mCurrentState; }
inline State& currentState() { return mCurrentState; }
void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const;
void setFiltering(bool filtering);
bool getFiltering() const;
private:
virtual sp<ISurface> createSurface();
Rect computeCrop(const sp<const DisplayDevice>& hw) const;
protected:
void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
GLclampf r, GLclampf g, GLclampf b, GLclampf alpha) const;
void drawWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip) const;
/*
* Trivial class, used to ensure that mFlinger->onLayerDestroyed(mLayer)
* is called.
*/
class LayerCleaner {
sp<SurfaceFlinger> mFlinger;
wp<LayerBase> mLayer;
protected:
~LayerCleaner();
public:
LayerCleaner(const sp<SurfaceFlinger>& flinger,
const sp<LayerBase>& layer);
};
sp<SurfaceFlinger> mFlinger;
private:
// accessed only in the main thread
// Whether filtering is forced on or not
bool mFiltering;
// Whether filtering is needed b/c of the drawingstate
bool mNeedsFiltering;
protected:
// these are protected by an external lock
State mCurrentState;
State mDrawingState;
volatile int32_t mTransactionFlags;
// don't change, don't need a lock
bool mPremultipliedAlpha;
String8 mName;
mutable bool mDebug;
private:
mutable Mutex mLock;
// Set to true if an ISurface has been associated with this object.
mutable bool mHasSurface;
// The ISurface's Binder object, set by getSurface().
wp<IBinder> mClientSurfaceBinder;
const wp<Client> mClientRef;
public:
// called from class SurfaceFlinger
virtual ~LayerBase();
private:
LayerBase(const LayerBase& rhs);
};
// ---------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_LAYER_BASE_H

View File

@ -34,12 +34,10 @@ namespace android {
// ---------------------------------------------------------------------------
LayerDim::LayerDim(SurfaceFlinger* flinger, const sp<Client>& client)
: Layer(flinger, client)
{
: Layer(flinger, client) {
}
LayerDim::~LayerDim()
{
LayerDim::~LayerDim() {
}
void LayerDim::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const
@ -77,7 +75,7 @@ sp<ISurface> LayerDim::createSurface()
virtual sp<IGraphicBufferProducer> getSurfaceTexture() const { return 0; }
public:
BSurface(const sp<SurfaceFlinger>& flinger,
const sp<LayerBase>& layer)
const sp<Layer>& layer)
: LayerCleaner(flinger, layer) { }
};
sp<ISurface> sur(new BSurface(mFlinger, this));
@ -85,7 +83,7 @@ sp<ISurface> LayerDim::createSurface()
}
bool LayerDim::isVisible() const {
const Layer::State& s(mDrawingState);
const Layer::State& s(drawingState());
return !(s.flags & layer_state_t::eLayerHidden) && s.alpha;
}

View File

@ -580,7 +580,7 @@ bool SurfaceFlinger::authenticateSurfaceTexture(
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(currentLayers[i]);
const sp<Layer>& layer(currentLayers[i]);
// If this is an instance of Layer (as opposed to, say, LayerDim),
// we will get the consumer interface of SurfaceFlingerConsumer's
// BufferQueue. If it's the same Binder object as the graphic
@ -600,7 +600,7 @@ bool SurfaceFlinger::authenticateSurfaceTexture(
// should not cause any harm.
size_t purgatorySize = mLayerPurgatory.size();
for (size_t i=0 ; i<purgatorySize ; i++) {
const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
const sp<Layer>& layer(mLayerPurgatory.itemAt(i));
wp<IBinder> lbcBinder = layer->getSurfaceTextureBinder();
if (lbcBinder == surfaceTextureBinder) {
return true;
@ -908,7 +908,7 @@ void SurfaceFlinger::rebuildLayerStacks() {
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
Region opaqueRegion;
Region dirtyRegion;
Vector< sp<LayerBase> > layersSortedByZ;
Vector< sp<Layer> > layersSortedByZ;
const sp<DisplayDevice>& hw(mDisplays[dpy]);
const Transform& tr(hw->getTransform());
const Rect bounds(hw->getBounds());
@ -918,7 +918,7 @@ void SurfaceFlinger::rebuildLayerStacks() {
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(currentLayers[i]);
const sp<Layer>& layer(currentLayers[i]);
const Layer::State& s(layer->drawingState());
if (s.layerStack == hw->getLayerStack()) {
Region drawRegion(tr.transform(
@ -948,14 +948,14 @@ void SurfaceFlinger::setUpHWComposer() {
sp<const DisplayDevice> hw(mDisplays[dpy]);
const int32_t id = hw->getHwcDisplayId();
if (id >= 0) {
const Vector< sp<LayerBase> >& currentLayers(
const Vector< sp<Layer> >& currentLayers(
hw->getVisibleLayersSortedByZ());
const size_t count = currentLayers.size();
if (hwc.createWorkList(id, count) == 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) {
const sp<LayerBase>& layer(currentLayers[i]);
const sp<Layer>& layer(currentLayers[i]);
layer->setGeometry(hw, *cur);
if (mDebugDisableHWC || mDebugRegion) {
cur->setSkip(true);
@ -971,7 +971,7 @@ void SurfaceFlinger::setUpHWComposer() {
sp<const DisplayDevice> hw(mDisplays[dpy]);
const int32_t id = hw->getHwcDisplayId();
if (id >= 0) {
const Vector< sp<LayerBase> >& currentLayers(
const Vector< sp<Layer> >& currentLayers(
hw->getVisibleLayersSortedByZ());
const size_t count = currentLayers.size();
HWComposer::LayerListIterator cur = hwc.begin(id);
@ -981,7 +981,7 @@ void SurfaceFlinger::setUpHWComposer() {
* update the per-frame h/w composer data for each layer
* and build the transparent region of the FB
*/
const sp<LayerBase>& layer(currentLayers[i]);
const sp<Layer>& layer(currentLayers[i]);
layer->setPerFrameData(hw, *cur);
}
}
@ -1035,7 +1035,7 @@ void SurfaceFlinger::postFramebuffer()
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ());
const Vector< sp<Layer> >& currentLayers(hw->getVisibleLayersSortedByZ());
hw->onSwapBuffersCompleted(hwc);
const size_t count = currentLayers.size();
int32_t id = hw->getHwcDisplayId();
@ -1091,7 +1091,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
if (transactionFlags & eTraversalNeeded) {
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(currentLayers[i]);
const sp<Layer>& layer(currentLayers[i]);
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) continue;
@ -1238,8 +1238,8 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
// NOTE: we rely on the fact that layers are sorted by
// layerStack first (so we don't have to traverse the list
// of displays for every layer).
const sp<LayerBase>& layerBase(currentLayers[i]);
uint32_t layerStack = layerBase->drawingState().layerStack;
const sp<Layer>& layer(currentLayers[i]);
uint32_t layerStack = layer->drawingState().layerStack;
if (i==0 || currentlayerStack != layerStack) {
currentlayerStack = layerStack;
// figure out if this layerstack is mirrored
@ -1261,7 +1261,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
if (disp != NULL) {
// presumably this means this layer is using a layerStack
// that is not visible on any display
layerBase->updateTransformHint(disp);
layer->updateTransformHint(disp);
}
}
}
@ -1284,7 +1284,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
mVisibleRegionsDirty = true;
const size_t count = previousLayers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(previousLayers[i]);
const sp<Layer>& layer(previousLayers[i]);
if (currentLayers.indexOf(layer) < 0) {
// this layer is not visible anymore
// TODO: we could traverse the tree from front to back and
@ -1335,7 +1335,7 @@ void SurfaceFlinger::computeVisibleRegions(
size_t i = currentLayers.size();
while (i--) {
const sp<LayerBase>& layer = currentLayers[i];
const sp<Layer>& layer = currentLayers[i];
// start with the whole surface at its current location
const Layer::State& s(layer->drawingState());
@ -1478,7 +1478,7 @@ void SurfaceFlinger::handlePageFlip()
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(currentLayers[i]);
const sp<Layer>& layer(currentLayers[i]);
const Region dirty(layer->latchBuffer(visibleRegions));
const Layer::State& s(layer->drawingState());
invalidateLayerStack(s.layerStack, dirty);
@ -1600,13 +1600,13 @@ void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const
* and then, render the layers targeted at the framebuffer
*/
const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ());
const Vector< sp<Layer> >& layers(hw->getVisibleLayersSortedByZ());
const size_t count = layers.size();
const Transform& tr = hw->getTransform();
if (cur != end) {
// we're using h/w composer
for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) {
const sp<LayerBase>& layer(layers[i]);
const sp<Layer>& layer(layers[i]);
const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
if (!clip.isEmpty()) {
switch (cur->getCompositionType()) {
@ -1638,7 +1638,7 @@ void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const
} else {
// we're not using h/w composer
for (size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer(layers[i]);
const sp<Layer>& layer(layers[i]);
const Region clip(dirty.intersect(
tr.transform(layer->visibleRegion)));
if (!clip.isEmpty()) {
@ -1677,7 +1677,7 @@ void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw,
void SurfaceFlinger::addClientLayer(const sp<Client>& client,
const sp<IBinder>& handle,
const sp<LayerBase>& lbc)
const sp<Layer>& lbc)
{
// attach this layer to the client
client->attachLayer(handle, lbc);
@ -1687,7 +1687,7 @@ void SurfaceFlinger::addClientLayer(const sp<Client>& client,
mCurrentState.layersSortedByZ.add(lbc);
}
status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)
status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer)
{
Mutex::Autolock _l(mStateLock);
status_t err = purgatorizeLayer_l(layer);
@ -1696,9 +1696,9 @@ status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)
return err;
}
status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase)
status_t SurfaceFlinger::removeLayer_l(const sp<Layer>& layer)
{
ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase);
ssize_t index = mCurrentState.layersSortedByZ.remove(layer);
if (index >= 0) {
mLayersRemoved = true;
return NO_ERROR;
@ -1706,16 +1706,16 @@ status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase)
return status_t(index);
}
status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase)
status_t SurfaceFlinger::purgatorizeLayer_l(const sp<Layer>& layer)
{
// First add the layer to the purgatory list, which makes sure it won't
// go away, then remove it from the main list (through a transaction).
ssize_t err = removeLayer_l(layerBase);
ssize_t err = removeLayer_l(layer);
if (err >= 0) {
mLayerPurgatory.add(layerBase);
mLayerPurgatory.add(layer);
}
mLayersPendingRemoval.push(layerBase);
mLayersPendingRemoval.push(layer);
// it's possible that we don't find a layer, because it might
// have been destroyed already -- this is not technically an error
@ -1866,7 +1866,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(
const layer_state_t& s)
{
uint32_t flags = 0;
sp<LayerBase> layer(client->getLayerUser(s.surface));
sp<Layer> layer(client->getLayerUser(s.surface));
if (layer != 0) {
const uint32_t what = s.what;
if (what & layer_state_t::ePositionChanged) {
@ -1930,7 +1930,7 @@ sp<ISurface> SurfaceFlinger::createLayer(
uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags)
{
sp<LayerBase> layer;
sp<Layer> layer;
sp<ISurface> surfaceHandle;
if (int32_t(w|h) < 0) {
@ -2017,7 +2017,7 @@ status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBind
status_t err = NAME_NOT_FOUND;
Mutex::Autolock _l(mStateLock);
sp<LayerBase> layer = client->getLayerUser(handle);
sp<Layer> layer = client->getLayerUser(handle);
if (layer != 0) {
err = purgatorizeLayer_l(layer);
@ -2028,11 +2028,11 @@ status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBind
return err;
}
status_t SurfaceFlinger::onLayerDestroyed(const wp<LayerBase>& layer)
status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer)
{
// called by ~ISurface() when all references are gone
status_t err = NO_ERROR;
sp<LayerBase> l(layer.promote());
sp<Layer> l(layer.promote());
if (l != NULL) {
Mutex::Autolock _l(mStateLock);
err = removeLayer_l(l);
@ -2249,7 +2249,7 @@ void SurfaceFlinger::listLayersLocked(const Vector<String16>& args, size_t& inde
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(currentLayers[i]);
const sp<Layer>& layer(currentLayers[i]);
snprintf(buffer, SIZE, "%s\n", layer->getName().string());
result.append(buffer);
}
@ -2274,7 +2274,7 @@ void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(currentLayers[i]);
const sp<Layer>& layer(currentLayers[i]);
if (name == layer->getName()) {
layer->dumpStats(result, buffer, SIZE);
}
@ -2294,7 +2294,7 @@ void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& inde
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
const size_t count = currentLayers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(currentLayers[i]);
const sp<Layer>& layer(currentLayers[i]);
if (name.isEmpty() || (name == layer->getName())) {
layer->clearStats();
}
@ -2350,7 +2350,7 @@ void SurfaceFlinger::dumpAllLocked(
snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count);
result.append(buffer);
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(currentLayers[i]);
const sp<Layer>& layer(currentLayers[i]);
layer->dump(result, buffer, SIZE);
}
@ -2362,7 +2362,7 @@ void SurfaceFlinger::dumpAllLocked(
snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
result.append(buffer);
for (size_t i=0 ; i<purgatorySize ; i++) {
const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
const sp<Layer>& layer(mLayerPurgatory.itemAt(i));
layer->shortDump(result, buffer, SIZE);
}
@ -2451,7 +2451,7 @@ void SurfaceFlinger::dumpAllLocked(
alloc.dump(result);
}
const Vector< sp<LayerBase> >&
const Vector< sp<Layer> >&
SurfaceFlinger::getLayerSortedByZForHwcDisplay(int disp) {
// Note: mStateLock is held here
return getDisplayDevice( getBuiltInDisplay(disp) )->getVisibleLayersSortedByZ();
@ -2708,10 +2708,10 @@ status_t SurfaceFlinger::captureScreenImplLocked(
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ());
const Vector< sp<Layer> >& layers(hw->getVisibleLayersSortedByZ());
const size_t count = layers.size();
for (size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer(layers[i]);
const sp<Layer>& layer(layers[i]);
const uint32_t z = layer->drawingState().z;
if (z >= minLayerZ && z <= maxLayerZ) {
if (filtering) layer->setFiltering(true);
@ -2874,15 +2874,15 @@ SurfaceFlinger::LayerVector::LayerVector() {
}
SurfaceFlinger::LayerVector::LayerVector(const LayerVector& rhs)
: SortedVector<sp<LayerBase> >(rhs) {
: SortedVector<sp<Layer> >(rhs) {
}
int SurfaceFlinger::LayerVector::do_compare(const void* lhs,
const void* rhs) const
{
// sort layers per layer-stack, then by z-order and finally by sequence
const sp<LayerBase>& l(*reinterpret_cast<const sp<LayerBase>*>(lhs));
const sp<LayerBase>& r(*reinterpret_cast<const sp<LayerBase>*>(rhs));
const sp<Layer>& l(*reinterpret_cast<const sp<Layer>*>(lhs));
const sp<Layer>& r(*reinterpret_cast<const sp<Layer>*>(rhs));
uint32_t ls = l->currentState().layerStack;
uint32_t rs = r->currentState().layerStack;

View File

@ -60,7 +60,6 @@ class DisplayEventConnection;
class EventThread;
class IGraphicBufferAlloc;
class Layer;
class LayerBase;
class LayerDim;
class Surface;
@ -123,12 +122,11 @@ public:
// for debugging only
// TODO: this should be made accessible only to HWComposer
const Vector< sp<LayerBase> >& getLayerSortedByZForHwcDisplay(int disp);
const Vector< sp<Layer> >& getLayerSortedByZForHwcDisplay(int disp);
private:
friend class Client;
friend class DisplayEventConnection;
friend class LayerBase;
friend class Layer;
// We're reference counted, never destroy SurfaceFlinger directly
@ -138,7 +136,7 @@ private:
* Internal data structures
*/
class LayerVector : public SortedVector<sp<LayerBase> > {
class LayerVector : public SortedVector< sp<Layer> > {
public:
LayerVector();
LayerVector(const LayerVector& rhs);
@ -277,17 +275,17 @@ private:
// called when all clients have released all their references to
// this layer meaning it is entirely safe to destroy all
// resources associated to this layer.
status_t onLayerDestroyed(const wp<LayerBase>& layer);
status_t onLayerDestroyed(const wp<Layer>& layer);
// remove a layer from SurfaceFlinger immediately
status_t removeLayer(const sp<LayerBase>& layer);
status_t removeLayer(const sp<Layer>& layer);
// add a layer to SurfaceFlinger
void addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<LayerBase>& lbc);
const sp<Layer>& lbc);
status_t removeLayer_l(const sp<LayerBase>& layer);
status_t purgatorizeLayer_l(const sp<LayerBase>& layer);
status_t removeLayer_l(const sp<Layer>& layer);
status_t purgatorizeLayer_l(const sp<Layer>& layer);
/* ------------------------------------------------------------------------
* Boot animation, on/off animations and screen capture
@ -401,10 +399,10 @@ private:
State mCurrentState;
volatile int32_t mTransactionFlags;
Condition mTransactionCV;
SortedVector<sp<LayerBase> > mLayerPurgatory;
SortedVector< sp<Layer> > mLayerPurgatory;
bool mTransactionPending;
bool mAnimTransactionPending;
Vector<sp<LayerBase> > mLayersPendingRemoval;
Vector< sp<Layer> > mLayersPendingRemoval;
// protected by mStateLock (but we could use another lock)
bool mLayersRemoved;
@ -453,7 +451,7 @@ private:
// protected by mDestroyedLayerLock;
mutable Mutex mDestroyedLayerLock;
Vector<LayerBase const *> mDestroyedLayers;
Vector<Layer const *> mDestroyedLayers;
/* ------------------------------------------------------------------------
* Feature prototyping