#include <gui/Surface.h>
#include "clz.h"
+#include "Colorizer.h"
#include "DisplayDevice.h"
#include "GLExtensions.h"
#include "Layer.h"
int32_t Layer::sSequence = 1;
-Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client)
+Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags)
: contentDirty(false),
sequence(uint32_t(android_atomic_inc(&sSequence))),
mFlinger(flinger),
{
mCurrentCrop.makeInvalid();
glGenTextures(1, &mTextureName);
+
+ uint32_t layerFlags = 0;
+ if (flags & ISurfaceComposerClient::eHidden)
+ layerFlags = layer_state_t::eLayerHidden;
+
+ if (flags & ISurfaceComposerClient::eNonPremultiplied)
+ mPremultipliedAlpha = false;
+
+ mName = name;
+
+ 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;
}
void Layer::onFirstRef()
{
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
- sp<BufferQueue> bq = new SurfaceTextureLayer();
+ sp<BufferQueue> bq = new SurfaceTextureLayer(mFlinger);
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mTextureName, true,
GL_TEXTURE_EXTERNAL_OES, false, bq);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setFrameAvailableListener(this);
mSurfaceFlingerConsumer->setSynchronousMode(true);
+ mSurfaceFlingerConsumer->setName(mName);
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
updateTransformHint(hw);
}
-Layer::~Layer()
-{
+Layer::~Layer() {
sp<Client> c(mClientRef.promote());
if (c != 0) {
c->detachLayer(this);
HWComposer::HWCLayerInterface* layer) {
if (layer) {
layer->onDisplayed();
- mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFenceFd());
+ mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFence());
}
}
mFlinger->signalLayerUpdate();
}
-// called with SurfaceFlinger::mStateLock as soon as the layer is entered
-// in the purgatory list
+// called with SurfaceFlinger::mStateLock from the drawing thread after
+// the layer has been remove from the current state list (and just before
+// it's removed from the drawing state list)
void Layer::onRemoved() {
mSurfaceFlingerConsumer->abandon();
}
// set-up
// ---------------------------------------------------------------------------
-void Layer::setName(const String8& name) {
- mName = name;
- mSurfaceFlingerConsumer->setName(name);
-}
-
String8 Layer::getName() const {
return mName;
}
-void Layer::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;
-}
-
status_t Layer::setBuffers( uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags)
{
return NO_ERROR;
}
-sp<ISurface> Layer::createSurface() {
+sp<IBinder> Layer::getHandle() {
+ Mutex::Autolock _l(mLock);
+
+ LOG_ALWAYS_FATAL_IF(mHasSurface,
+ "Layer::getHandle() has already been called");
+
+ mHasSurface = true;
+
/*
- * 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 handle is just a BBinder object passed to the client
+ * (remote process) -- we don't keep any reference on our side such that
+ * the dtor is called when the remote side let go of its reference.
*
- * 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.
+ * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for
+ * this layer when the handle is destroyed.
*/
- class BSurface : public BnSurface, public LayerCleaner {
+
+ class Handle : public BBinder, 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) { }
+ Handle(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();
+ return new Handle(mFlinger, this);
}
-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;
+sp<BufferQueue> Layer::getBufferQueue() const {
+ return mSurfaceFlingerConsumer->getBufferQueue();
}
+//virtual sp<IGraphicBufferProducer> getSurfaceTexture() const {
+// sp<IGraphicBufferProducer> res;
+// sp<const Layer> that( mOwner.promote() );
+// if (that != NULL) {
+// res = that->mSurfaceFlingerConsumer->getBufferQueue();
+// }
+// return res;
+//}
+
// ---------------------------------------------------------------------------
// h/w composer set-up
// ---------------------------------------------------------------------------
return mCurrentTransform;
}
+static Rect reduce(const Rect& win, const Region& exclude) {
+ if (CC_LIKELY(exclude.isEmpty())) {
+ return win;
+ }
+ if (exclude.isRect()) {
+ return win.reduce(exclude.getBounds());
+ }
+ return Region(win).subtract(exclude).getBounds();
+}
+
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;
+ // subtract the transparent region and snap to the bounds
+ return reduce(win, s.activeTransparentRegion);
}
Rect Layer::computeCrop(const sp<const DisplayDevice>& hw) const {
// window's bounds
activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop);
+ // subtract the transparent region and snap to the bounds
+ activeCrop = reduce(activeCrop, s.activeTransparentRegion);
+
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
clearWithOpenGL(hw, clip, 0,0,0,0);
}
+static void setupOpenGL10(bool premultipliedAlpha, bool opaque, int alpha) {
+ // OpenGL ES 1.0 doesn't support texture combiners.
+ // This path doesn't properly handle opaque layers that have non-opaque
+ // alpha values. The alpha channel will be copied into the framebuffer or
+ // screenshot, so if the framebuffer or screenshot is blended on top of
+ // something else, whatever is below the window will incorrectly show
+ // through.
+ if (CC_UNLIKELY(alpha < 0xFF)) {
+ GLfloat floatAlpha = alpha * (1.0f / 255.0f);
+ if (premultipliedAlpha) {
+ glColor4f(floatAlpha, floatAlpha, floatAlpha, floatAlpha);
+ } else {
+ glColor4f(1.0f, 1.0f, 1.0f, floatAlpha);
+ }
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ } else {
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ }
+}
+
+static void setupOpenGL11(bool premultipliedAlpha, bool opaque, int alpha) {
+ GLenum combineRGB;
+ GLenum combineAlpha;
+ GLenum src0Alpha;
+ GLfloat envColor[4];
+
+ if (CC_UNLIKELY(alpha < 0xFF)) {
+ // Cv = premultiplied ? Cs*alpha : Cs
+ // Av = !opaque ? alpha*As : 1.0
+ combineRGB = premultipliedAlpha ? GL_MODULATE : GL_REPLACE;
+ combineAlpha = !opaque ? GL_MODULATE : GL_REPLACE;
+ src0Alpha = GL_CONSTANT;
+ envColor[0] = alpha * (1.0f / 255.0f);
+ } else {
+ // Cv = Cs
+ // Av = opaque ? 1.0 : As
+ combineRGB = GL_REPLACE;
+ combineAlpha = GL_REPLACE;
+ src0Alpha = opaque ? GL_CONSTANT : GL_TEXTURE;
+ envColor[0] = 1.0f;
+ }
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, combineRGB);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ if (combineRGB == GL_MODULATE) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ }
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, combineAlpha);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, src0Alpha);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ if (combineAlpha == GL_MODULATE) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+ }
+ if (combineRGB == GL_MODULATE || src0Alpha == GL_CONSTANT) {
+ envColor[1] = envColor[0];
+ envColor[2] = envColor[0];
+ envColor[3] = envColor[0];
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor);
+ }
+}
+
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);
- }
+ if (mFlinger->getGlesVersion() == GLES_VERSION_1_0) {
+ setupOpenGL10(mPremultipliedAlpha, isOpaque(), s.alpha);
+ } else {
+ setupOpenGL11(mPremultipliedAlpha, isOpaque(), s.alpha);
+ }
+
+ if (s.alpha < 0xFF || !isOpaque()) {
glEnable(GL_BLEND);
- glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glBlendFunc(mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA,
+ GL_ONE_MINUS_SRC_ALPHA);
} 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);
- }
+ glDisable(GL_BLEND);
}
LayerMesh mesh;
if (!s.active.crop.isEmpty()) {
win.intersect(s.active.crop, &win);
}
+ // subtract the transparent region and snap to the bounds
+ win = reduce(win, s.activeTransparentRegion);
if (mesh) {
tr.transform(mesh->mVertices[0], win.left, win.top);
tr.transform(mesh->mVertices[1], win.left, win.bottom);
return true;
}
bool Layer::setTransparentRegionHint(const Region& transparent) {
- mCurrentState.sequence++;
- mCurrentState.transparentRegion = transparent;
+ mCurrentState.requestedTransparentRegion = transparent;
setTransactionFlags(eTransactionNeeded);
return true;
}
swap(bufWidth, bufHeight);
}
-
bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
if (front.active != front.requested) {
return true;
}
}
+
+ // if the transparent region has changed (this test is
+ // conservative, but that's fine, worst case we're doing
+ // a bit of extra work), we latch the new one and we
+ // trigger a visible-region recompute.
+ if (!front.activeTransparentRegion.isTriviallyEqual(
+ front.requestedTransparentRegion)) {
+ front.activeTransparentRegion = front.requestedTransparentRegion;
+
+ // We also need to update the current state so that
+ // we don't end-up overwriting the drawing state with
+ // this stale current state during the next transaction
+ //
+ // NOTE: We don't need to hold the transaction lock here
+ // because State::active is only accessed from this thread.
+ current.activeTransparentRegion = front.activeTransparentRegion;
+
+ // recompute visible region
+ recomputeVisibleRegions = true;
+ }
+
return false;
}
};
// debugging
// ----------------------------------------------------------------------------
-void Layer::dump(String8& result, char* buffer, size_t SIZE) const
+void Layer::dump(String8& result, Colorizer& colorizer) const
{
const Layer::State& s(drawingState());
- snprintf(buffer, SIZE,
+ colorizer.colorize(result, Colorizer::GREEN);
+ result.appendFormat(
"+ %s %p (%s)\n",
getTypeId(), this, getName().string());
- result.append(buffer);
+ colorizer.reset(result);
- s.transparentRegion.dump(result, "transparentRegion");
+ s.activeTransparentRegion.dump(result, "transparentRegion");
visibleRegion.dump(result, "visibleRegion");
sp<Client> client(mClientRef.promote());
- snprintf(buffer, SIZE,
- " "
+ result.appendFormat( " "
"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"
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;
s0 = buf0->getStride();
f0 = buf0->format;
}
- snprintf(buffer, SIZE,
+ result.appendFormat(
" "
"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);
+ mSurfaceFlingerConsumer->dump(result, " ");
}
}
-
-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 {
+void Layer::dumpStats(String8& result) const {
mFrameTracker.dump(result);
}