diff options
Diffstat (limited to 'services/surfaceflinger/Layer.cpp')
-rw-r--r-- | services/surfaceflinger/Layer.cpp | 839 |
1 files changed, 655 insertions, 184 deletions
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 7edbdc5..4779804 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -50,116 +50,122 @@ namespace android { // --------------------------------------------------------------------------- -Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client) - : LayerBaseClient(flinger, client), +int32_t Layer::sSequence = 1; + +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), 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), - mFrameLatencyOffset(0), - 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) { - LayerBaseClient::onLayerDisplayed(hw, layer); - if (layer) { - mSurfaceTexture->setReleaseFence(layer->getAndResetReleaseFenceFd()); - } + 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() { - LayerBaseClient::onFirstRef(); - - struct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener { - FrameQueuedListener(Layer* layer) : mLayer(layer) { } - private: - wp<Layer> mLayer; - virtual void onFrameAvailable() { - sp<Layer> that(mLayer.promote()); - if (that != 0) { - that->onFrameQueued(); - } - } - }; - - // Creates a custom BufferQueue for SurfaceTexture to use - sp<BufferQueue> bq = new SurfaceTextureLayer(); - mSurfaceTexture = new SurfaceTexture(mTextureName, true, + // Creates a custom BufferQueue for SurfaceFlingerConsumer to use + sp<BufferQueue> bq = new SurfaceTextureLayer(mFlinger); + mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mTextureName, true, GL_TEXTURE_EXTERNAL_OES, false, bq); - mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0)); - mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this)); - mSurfaceTexture->setSynchronousMode(true); + mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0)); + mSurfaceFlingerConsumer->setFrameAvailableListener(this); + mSurfaceFlingerConsumer->setSynchronousMode(true); + mSurfaceFlingerConsumer->setName(mName); #ifdef TARGET_DISABLE_TRIPLE_BUFFERING #warning "disabling triple buffering" - mSurfaceTexture->setDefaultMaxBufferCount(2); + mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2); #else - mSurfaceTexture->setDefaultMaxBufferCount(3); + mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3); #endif const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice()); updateTransformHint(hw); } -Layer::~Layer() -{ +Layer::~Layer() { + sp<Client> c(mClientRef.promote()); + if (c != 0) { + c->detachLayer(this); + } mFlinger->deleteTextureAsync(mTextureName); } -void Layer::onFrameQueued() { - android_atomic_inc(&mQueuedFrames); - mFlinger->signalLayerUpdate(); -} +// --------------------------------------------------------------------------- +// callbacks +// --------------------------------------------------------------------------- -// called with SurfaceFlinger::mStateLock as soon as the layer is entered -// in the purgatory list -void Layer::onRemoved() -{ - mSurfaceTexture->abandon(); +void Layer::onLayerDisplayed(const sp<const DisplayDevice>& hw, + HWComposer::HWCLayerInterface* layer) { + if (layer) { + layer->onDisplayed(); + mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFence()); + } } -void Layer::setName(const String8& name) { - LayerBase::setName(name); - mSurfaceTexture->setName(name); +void Layer::onFrameAvailable() { + android_atomic_inc(&mQueuedFrames); + mFlinger->signalLayerUpdate(); } -sp<ISurface> Layer::createSurface() -{ - class BSurface : public BnSurface, public LayerCleaner { - wp<const Layer> mOwner; - virtual sp<ISurfaceTexture> getSurfaceTexture() const { - sp<ISurfaceTexture> res; - sp<const Layer> that( mOwner.promote() ); - if (that != NULL) { - res = that->mSurfaceTexture->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; +// 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(); } -wp<IBinder> Layer::getSurfaceTextureBinder() const -{ - return mSurfaceTexture->getBufferQueue()->asBinder(); +// --------------------------------------------------------------------------- +// set-up +// --------------------------------------------------------------------------- + +String8 Layer::getName() const { + return mName; } status_t Layer::setBuffers( uint32_t w, uint32_t h, @@ -190,33 +196,124 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, mOpaqueLayer = (flags & ISurfaceComposerClient::eOpaque); mCurrentOpacity = getOpacityForFormat(format); - mSurfaceTexture->setDefaultBufferSize(w, h); - mSurfaceTexture->setDefaultBufferFormat(format); - mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0)); + mSurfaceFlingerConsumer->setDefaultBufferSize(w, h); + mSurfaceFlingerConsumer->setDefaultBufferFormat(format); + mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0)); return NO_ERROR; } -Rect Layer::computeBufferCrop() const { - // Start with the SurfaceTexture's buffer crop... +sp<IBinder> Layer::getHandle() { + Mutex::Autolock _l(mLock); + + LOG_ALWAYS_FATAL_IF(mHasSurface, + "Layer::getHandle() has already been called"); + + mHasSurface = true; + + /* + * 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. + * + * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for + * this layer when the handle is destroyed. + */ + + class Handle : public BBinder, public LayerCleaner { + wp<const Layer> mOwner; + public: + Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer) + : LayerCleaner(flinger, layer), mOwner(layer) { + } + }; + + return new Handle(mFlinger, this); +} + +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 +// --------------------------------------------------------------------------- + +Rect Layer::getContentCrop() const { + // this is the crop rectangle that applies to the buffer + // itself (as opposed to the window) Rect crop; if (!mCurrentCrop.isEmpty()) { + // if the buffer crop is defined, we use that crop = mCurrentCrop; - } else if (mActiveBuffer != NULL){ - crop = Rect(mActiveBuffer->getWidth(), mActiveBuffer->getHeight()); + } else if (mActiveBuffer != NULL) { + // otherwise we use the whole buffer + crop = mActiveBuffer->getBounds(); } else { + // if we don't have a buffer yet, we use an empty/invalid crop crop.makeInvalid(); - return crop; } + return crop; +} - // ... then reduce that in the same proportions as the window crop reduces - // the window size. - const State& s(drawingState()); +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 - // SurfaceTexture. - uint32_t invTransform = mCurrentTransform; + // SurfaceFlingerConsumer. + uint32_t invTransform = getContentTransform(); int winWidth = s.active.w; int winHeight = s.active.h; if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { @@ -225,17 +322,24 @@ Rect Layer::computeBufferCrop() const { winWidth = s.active.h; winHeight = s.active.w; } - Rect winCrop = s.active.crop.transform(invTransform, - s.active.w, s.active.h); + 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); - crop.left += int(ceilf(float(winCrop.left) * xScale)); - crop.top += int(ceilf(float(winCrop.top) * yScale)); - crop.right -= int(ceilf(float(winWidth - winCrop.right) * xScale)); - crop.bottom -= int(ceilf(float(winHeight - winCrop.bottom) * yScale)); - } + 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; } @@ -243,21 +347,32 @@ void Layer::setGeometry( const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer) { - LayerBaseClient::setGeometry(hw, layer); + layer.setDefaultState(); // enable this layer layer.setSkip(false); - // we can't do alpha-fade with the hwc HAL - const State& s(drawingState()); - if (s.alpha < 0xFF) { + if (isSecure() && !hw->isSecure()) { layer.setSkip(true); } - if (isSecure() && !hw->isSecure()) { - 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); + /* * Transformations are applied in this order: * 1) buffer orientation/flip/mirror @@ -267,23 +382,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); } - layer.setCrop(computeBufferCrop()); } void Layer::setPerFrameData(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer) { - LayerBaseClient::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); @@ -297,8 +418,8 @@ void Layer::setAcquireFence(const sp<const DisplayDevice>& hw, // acquire fence the first time a new buffer is acquired on EACH display. if (layer.getCompositionType() == HWC_OVERLAY) { - sp<Fence> fence = mSurfaceTexture->getCurrentFence(); - if (fence.get()) { + sp<Fence> fence = mSurfaceFlingerConsumer->getCurrentFence(); + if (fence->isValid()) { fenceFd = fence->dup(); if (fenceFd == -1) { ALOGW("failed to dup layer fence, skipping sync: %d", errno); @@ -308,6 +429,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(); @@ -327,8 +460,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) ); } @@ -340,9 +473,11 @@ void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const return; } - status_t err = mSurfaceTexture->doGLFenceWait(); - if (err != OK) { - ALOGE("onDraw: failed waiting for fence: %d", err); + // Bind the current buffer to the GL texture, and wait for it to be + // ready for us to draw into. + status_t err = mSurfaceFlingerConsumer->bindTextureImage(); + if (err != NO_ERROR) { + ALOGW("onDraw: bindTextureImage failed (err=%d)", err); // Go ahead and draw the buffer anyway; no matter what we do the screen // is probably going to have something visibly wrong. } @@ -355,8 +490,8 @@ void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const // Query the texture matrix given our current filtering mode. float textureMatrix[16]; - mSurfaceTexture->setFilteringEnabled(useFiltering); - mSurfaceTexture->getTransformMatrix(textureMatrix); + mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering); + mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix); // Set things up for texturing. glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureName); @@ -386,6 +521,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 @@ -404,6 +652,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 { @@ -425,8 +696,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()); @@ -475,7 +777,7 @@ uint32_t Layer::doTransaction(uint32_t flags) // record the new size, form this point on, when the client request // a buffer, it'll get the new size. - mSurfaceTexture->setDefaultBufferSize( + mSurfaceFlingerConsumer->setDefaultBufferSize( temp.requested.w, temp.requested.h); } @@ -485,7 +787,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. @@ -498,15 +800,116 @@ 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.requestedTransparentRegion = 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; } // ---------------------------------------------------------------------------- @@ -520,18 +923,38 @@ bool Layer::onPreComposition() { void Layer::onPostComposition() { if (mFrameLatencyNeeded) { + nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp(); + mFrameTracker.setDesiredPresentTime(desiredPresentTime); + + sp<Fence> frameReadyFence = mSurfaceFlingerConsumer->getCurrentFence(); + if (frameReadyFence->isValid()) { + mFrameTracker.setFrameReadyFence(frameReadyFence); + } else { + // There was no fence for this frame, so assume that it was ready + // to be presented at the desired present time. + mFrameTracker.setFrameReadyTime(desiredPresentTime); + } + const HWComposer& hwc = mFlinger->getHwComposer(); - const size_t offset = mFrameLatencyOffset; - mFrameStats[offset].timestamp = mSurfaceTexture->getTimestamp(); - mFrameStats[offset].set = systemTime(); - mFrameStats[offset].vsync = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY); - mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128; + sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY); + if (presentFence->isValid()) { + mFrameTracker.setActualPresentFence(presentFence); + } else { + // The HWC doesn't support present fences, so use the refresh + // timestamp instead. + nsecs_t presentTime = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY); + mFrameTracker.setActualPresentTime(presentTime); + } + + mFrameTracker.advanceFrame(); mFrameLatencyNeeded = false; } } bool Layer::isVisible() const { - return LayerBaseClient::isVisible() && (mActiveBuffer != NULL); + const Layer::State& s(mDrawingState); + return !(s.flags & layer_state_t::eLayerHidden) && s.alpha + && (mActiveBuffer != NULL); } Region Layer::latchBuffer(bool& recomputeVisibleRegions) @@ -559,7 +982,7 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) mFlinger->signalLayerUpdate(); } - struct Reject : public SurfaceTexture::BufferRejecter { + struct Reject : public SurfaceFlingerConsumer::BufferRejecter { Layer::State& front; Layer::State& current; bool& recomputeVisibleRegions; @@ -584,7 +1007,6 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) swap(bufWidth, bufHeight); } - bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE; if (front.active != front.requested) { @@ -637,6 +1059,27 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) 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; } }; @@ -644,14 +1087,14 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) Reject r(mDrawingState, currentState(), recomputeVisibleRegions); - if (mSurfaceTexture->updateTexImage(&r, true) < NO_ERROR) { + if (mSurfaceFlingerConsumer->updateTexImage(&r) != NO_ERROR) { // something happened! recomputeVisibleRegions = true; return outDirtyRegion; } // update the active buffer - mActiveBuffer = mSurfaceTexture->getCurrentBuffer(); + mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer(); if (mActiveBuffer == NULL) { // this can only happen if the very first buffer was rejected. return outDirtyRegion; @@ -665,9 +1108,9 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) recomputeVisibleRegions = true; } - Rect crop(mSurfaceTexture->getCurrentCrop()); - const uint32_t transform(mSurfaceTexture->getCurrentTransform()); - const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode()); + Rect crop(mSurfaceFlingerConsumer->getCurrentCrop()); + const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform()); + const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode()); if ((crop != mCurrentCrop) || (transform != mCurrentTransform) || (scalingMode != mCurrentScalingMode)) @@ -705,9 +1148,64 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) return outDirtyRegion; } +uint32_t Layer::getEffectiveUsage(uint32_t usage) const +{ + // TODO: should we do something special if mSecure is set? + if (mProtectedByApp) { + // need a hardware-protected path to external video sink + usage |= GraphicBuffer::USAGE_PROTECTED; + } + usage |= GraphicBuffer::USAGE_HW_COMPOSER; + return usage; +} + +void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const { + uint32_t orientation = 0; + if (!mFlinger->mDebugDisableTransformHint) { + // The transform hint is used to improve performance, but we can + // only have a single transform hint, it cannot + // apply to all displays. + const Transform& planeTransform(hw->getTransform()); + orientation = planeTransform.getOrientation(); + if (orientation & Transform::ROT_INVALID) { + orientation = 0; + } + } + mSurfaceFlingerConsumer->setTransformHint(orientation); +} + +// ---------------------------------------------------------------------------- +// debugging +// ---------------------------------------------------------------------------- + void Layer::dump(String8& result, char* buffer, size_t SIZE) const { - LayerBaseClient::dump(result, buffer, SIZE); + const Layer::State& s(drawingState()); + + snprintf(buffer, SIZE, + "+ %s %p (%s)\n", + getTypeId(), this, getName().string()); + result.append(buffer); + + s.activeTransparentRegion.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; @@ -726,61 +1224,34 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const result.append(buffer); - if (mSurfaceTexture != 0) { - mSurfaceTexture->dump(result, " ", buffer, SIZE); + if (mSurfaceFlingerConsumer != 0) { + mSurfaceFlingerConsumer->dump(result, " ", buffer, SIZE); } } -void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const -{ - LayerBaseClient::dumpStats(result, buffer, SIZE); - const size_t o = mFrameLatencyOffset; - const nsecs_t period = - mFlinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); - result.appendFormat("%lld\n", period); - for (size_t i=0 ; i<128 ; i++) { - const size_t index = (o+i) % 128; - const nsecs_t time_app = mFrameStats[index].timestamp; - const nsecs_t time_set = mFrameStats[index].set; - const nsecs_t time_vsync = mFrameStats[index].vsync; - result.appendFormat("%lld\t%lld\t%lld\n", - time_app, - time_vsync, - time_set); - } - result.append("\n"); + +void Layer::shortDump(String8& result, char* scratch, size_t size) const { + Layer::dump(result, scratch, size); } -void Layer::clearStats() -{ - LayerBaseClient::clearStats(); - memset(mFrameStats, 0, sizeof(mFrameStats)); +void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const { + mFrameTracker.dump(result); } -uint32_t Layer::getEffectiveUsage(uint32_t usage) const -{ - // TODO: should we do something special if mSecure is set? - if (mProtectedByApp) { - // need a hardware-protected path to external video sink - usage |= GraphicBuffer::USAGE_PROTECTED; - } - usage |= GraphicBuffer::USAGE_HW_COMPOSER; - return usage; +void Layer::clearStats() { + mFrameTracker.clear(); } -void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const { - uint32_t orientation = 0; - if (!mFlinger->mDebugDisableTransformHint) { - // The transform hint is used to improve performance, but we can - // only have a single transform hint, it cannot - // apply to all displays. - const Transform& planeTransform(hw->getTransform()); - orientation = planeTransform.getOrientation(); - if (orientation & Transform::ROT_INVALID) { - orientation = 0; - } - } - mSurfaceTexture->setTransformHint(orientation); +// --------------------------------------------------------------------------- + +Layer::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger, + const sp<Layer>& layer) + : mFlinger(flinger), mLayer(layer) { +} + +Layer::LayerCleaner::~LayerCleaner() { + // destroy client resources + mFlinger->onLayerDestroyed(mLayer); } // --------------------------------------------------------------------------- |