Refactor Layer/ColorLayer into siblings
New class hierarchy should look like:
Layer (abstract)
/ \
/ \
Buffer Color
Layer Layer
Note: LayerBuffer is what previously was referred to by class Layer
Test: Transaction_test.cpp/manual test
Change-Id: I372a27d533e08371da37be811e4372404f7787bd
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 3f8ab3f..7115ad6 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -14,6 +14,7 @@
FrameTracker.cpp \
GpuService.cpp \
Layer.cpp \
+ BufferLayer.cpp \
ColorLayer.cpp \
LayerRejecter.cpp \
LayerVector.cpp \
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
new file mode 100644
index 0000000..ccb65f6
--- /dev/null
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -0,0 +1,911 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "BufferLayer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "BufferLayer.h"
+#include "Colorizer.h"
+#include "DisplayDevice.h"
+#include "LayerRejecter.h"
+#include "clz.h"
+
+#include "RenderEngine/RenderEngine.h"
+
+#include <gui/BufferItem.h>
+#include <gui/BufferQueue.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/Surface.h>
+
+#include <ui/DebugUtils.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/NativeHandle.h>
+#include <utils/StopWatch.h>
+#include <utils/Trace.h>
+
+#include <cutils/compiler.h>
+#include <cutils/native_handle.h>
+#include <cutils/properties.h>
+
+#include <math.h>
+#include <stdlib.h>
+#include <mutex>
+
+namespace android {
+
+BufferLayer::BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+ uint32_t w, uint32_t h, uint32_t flags)
+ : Layer(flinger, client, name, w, h, flags),
+ mTextureName(-1U),
+ mFormat(PIXEL_FORMAT_NONE),
+ mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+ mBufferLatched(false),
+ mPreviousFrameNumber(0),
+ mUpdateTexImageFailed(false),
+ mRefreshPending(false) {
+#ifdef USE_HWC2
+ ALOGV("Creating Layer %s", name.string());
+#endif
+
+ mFlinger->getRenderEngine().genTextures(1, &mTextureName);
+ mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);
+
+ if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false;
+
+ mCurrentState.requested = mCurrentState.active;
+
+ // drawing state & current state are identical
+ mDrawingState = mCurrentState;
+}
+
+BufferLayer::~BufferLayer() {
+ sp<Client> c(mClientRef.promote());
+ if (c != 0) {
+ c->detachLayer(this);
+ }
+
+ for (auto& point : mRemoteSyncPoints) {
+ point->setTransactionApplied();
+ }
+ for (auto& point : mLocalSyncPoints) {
+ point->setFrameAvailable();
+ }
+ mFlinger->deleteTextureAsync(mTextureName);
+
+#ifdef USE_HWC2
+ if (!mHwcLayers.empty()) {
+ ALOGE("Found stale hardware composer layers when destroying "
+ "surface flinger layer %s",
+ mName.string());
+ destroyAllHwcLayers();
+ }
+#endif
+}
+
+bool BufferLayer::isProtected() const
+{
+ const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
+ return (activeBuffer != 0) &&
+ (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+}
+
+bool BufferLayer::isVisible() const {
+ return !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
+ (mActiveBuffer != NULL || mSidebandStream != NULL);
+}
+
+bool BufferLayer::isFixedSize() const {
+ return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE;
+}
+
+status_t BufferLayer::setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) {
+ uint32_t const maxSurfaceDims =
+ min(mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims());
+
+ // never allow a surface larger than what our underlying GL implementation
+ // can handle.
+ if ((uint32_t(w) > maxSurfaceDims) || (uint32_t(h) > maxSurfaceDims)) {
+ ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
+ return BAD_VALUE;
+ }
+
+ mFormat = format;
+
+ mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
+ mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
+ mCurrentOpacity = getOpacityForFormat(format);
+
+ mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
+ mSurfaceFlingerConsumer->setDefaultBufferFormat(format);
+ mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+
+ return NO_ERROR;
+}
+
+static constexpr mat4 inverseOrientation(uint32_t transform) {
+ const mat4 flipH(-1,0,0,0, 0,1,0,0, 0,0,1,0, 1,0,0,1);
+ const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1);
+ const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1);
+ mat4 tr;
+
+ if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ tr = tr * rot90;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+ tr = tr * flipH;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+ tr = tr * flipV;
+ }
+ return inverse(tr);
+}
+
+/*
+ * onDraw will draw the current layer onto the presentable buffer
+ */
+void BufferLayer::onDraw(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform) const {
+ ATRACE_CALL();
+
+ if (CC_UNLIKELY(mActiveBuffer == 0)) {
+ // the texture has not been created yet, this Layer has
+ // in fact never been drawn into. This happens frequently with
+ // SurfaceView because the WindowManager can't know when the client
+ // has drawn the first time.
+
+ // If there is nothing under us, we paint the screen in black, otherwise
+ // we just skip this update.
+
+ // figure out if there is something below us
+ Region under;
+ bool finished = false;
+ mFlinger->mDrawingState.traverseInZOrder([&](Layer* layer) {
+ if (finished || layer == static_cast<BufferLayer const*>(this)) {
+ finished = true;
+ return;
+ }
+ under.orSelf(renderArea.getTransform().transform(layer->visibleRegion));
+ });
+ // if not everything below us is covered, we plug the holes!
+ Region holes(clip.subtract(under));
+ if (!holes.isEmpty()) {
+ clearWithOpenGL(renderArea, 0, 0, 0, 1);
+ }
+ return;
+ }
+
+ // 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.
+ }
+
+ bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure());
+
+ RenderEngine& engine(mFlinger->getRenderEngine());
+
+ if (!blackOutLayer) {
+ // TODO: we could be more subtle with isFixedSize()
+ const bool useFiltering = getFiltering() || needsFiltering(renderArea) || isFixedSize();
+
+ // Query the texture matrix given our current filtering mode.
+ float textureMatrix[16];
+ mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
+ mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
+
+ if (getTransformToDisplayInverse()) {
+ /*
+ * the code below applies the primary display's inverse transform to
+ * the texture transform
+ */
+ uint32_t transform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+ mat4 tr = inverseOrientation(transform);
+
+ /**
+ * TODO(b/36727915): This is basically a hack.
+ *
+ * Ensure that regardless of the parent transformation,
+ * this buffer is always transformed from native display
+ * orientation to display orientation. For example, in the case
+ * of a camera where the buffer remains in native orientation,
+ * we want the pixels to always be upright.
+ */
+ sp<Layer> p = mDrawingParent.promote();
+ if (p != nullptr) {
+ const auto parentTransform = p->getTransform();
+ tr = tr * inverseOrientation(parentTransform.getOrientation());
+ }
+
+ // and finally apply it to the original texture matrix
+ const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
+ memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
+ }
+
+ // Set things up for texturing.
+ mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
+ mTexture.setFiltering(useFiltering);
+ mTexture.setMatrix(textureMatrix);
+
+ engine.setupLayerTexturing(mTexture);
+ } else {
+ engine.setupLayerBlackedOut();
+ }
+ drawWithOpenGL(renderArea, useIdentityTransform);
+ engine.disableTexturing();
+}
+
+bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
+ if (mBufferLatched) {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
+ }
+ mRefreshPending = false;
+ return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
+}
+
+#ifdef USE_HWC2
+void BufferLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
+ if (!mSurfaceFlingerConsumer->releasePendingBuffer()) {
+ return;
+ }
+
+ auto releaseFenceTime =
+ std::make_shared<FenceTime>(mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
+ mReleaseTimeline.updateSignalTimes();
+ mReleaseTimeline.push(releaseFenceTime);
+
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ if (mPreviousFrameNumber != 0) {
+ mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
+ std::move(releaseFenceTime));
+ }
+}
+#endif
+
+Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+ ATRACE_CALL();
+
+ if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
+ // mSidebandStreamChanged was true
+ mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
+ if (mSidebandStream != NULL) {
+ setTransactionFlags(eTransactionNeeded);
+ mFlinger->setTransactionFlags(eTraversalNeeded);
+ }
+ recomputeVisibleRegions = true;
+
+ const State& s(getDrawingState());
+ return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
+ }
+
+ Region outDirtyRegion;
+ if (mQueuedFrames <= 0 && !mAutoRefresh) {
+ return outDirtyRegion;
+ }
+
+ // if we've already called updateTexImage() without going through
+ // a composition step, we have to skip this layer at this point
+ // because we cannot call updateTeximage() without a corresponding
+ // compositionComplete() call.
+ // we'll trigger an update in onPreComposition().
+ if (mRefreshPending) {
+ return outDirtyRegion;
+ }
+
+ // If the head buffer's acquire fence hasn't signaled yet, return and
+ // try again later
+ if (!headFenceHasSignaled()) {
+ mFlinger->signalLayerUpdate();
+ return outDirtyRegion;
+ }
+
+ // Capture the old state of the layer for comparisons later
+ const State& s(getDrawingState());
+ const bool oldOpacity = isOpaque(s);
+ sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
+
+ if (!allTransactionsSignaled()) {
+ mFlinger->signalLayerUpdate();
+ return outDirtyRegion;
+ }
+
+ // This boolean is used to make sure that SurfaceFlinger's shadow copy
+ // of the buffer queue isn't modified when the buffer queue is returning
+ // BufferItem's that weren't actually queued. This can happen in shared
+ // buffer mode.
+ bool queuedBuffer = false;
+ LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
+ getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
+ mFreezeGeometryUpdates);
+ status_t updateResult =
+ mSurfaceFlingerConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync, &mAutoRefresh,
+ &queuedBuffer, mLastFrameNumberReceived);
+ if (updateResult == BufferQueue::PRESENT_LATER) {
+ // Producer doesn't want buffer to be displayed yet. Signal a
+ // layer update so we check again at the next opportunity.
+ mFlinger->signalLayerUpdate();
+ return outDirtyRegion;
+ } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
+ // If the buffer has been rejected, remove it from the shadow queue
+ // and return early
+ if (queuedBuffer) {
+ Mutex::Autolock lock(mQueueItemLock);
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ }
+ return outDirtyRegion;
+ } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
+ // This can occur if something goes wrong when trying to create the
+ // EGLImage for this buffer. If this happens, the buffer has already
+ // been released, so we need to clean up the queue and bug out
+ // early.
+ if (queuedBuffer) {
+ Mutex::Autolock lock(mQueueItemLock);
+ mQueueItems.clear();
+ android_atomic_and(0, &mQueuedFrames);
+ }
+
+ // Once we have hit this state, the shadow queue may no longer
+ // correctly reflect the incoming BufferQueue's contents, so even if
+ // updateTexImage starts working, the only safe course of action is
+ // to continue to ignore updates.
+ mUpdateTexImageFailed = true;
+
+ return outDirtyRegion;
+ }
+
+ if (queuedBuffer) {
+ // Autolock scope
+ auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
+ Mutex::Autolock lock(mQueueItemLock);
+
+ // Remove any stale buffers that have been dropped during
+ // updateTexImage
+ while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ }
+
+ mQueueItems.removeAt(0);
+ }
+
+ // Decrement the queued-frames count. Signal another event if we
+ // have more frames pending.
+ if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) || mAutoRefresh) {
+ mFlinger->signalLayerUpdate();
+ }
+
+ // update the active buffer
+ mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer(&mActiveBufferSlot);
+ if (mActiveBuffer == NULL) {
+ // this can only happen if the very first buffer was rejected.
+ return outDirtyRegion;
+ }
+
+ mBufferLatched = true;
+ mPreviousFrameNumber = mCurrentFrameNumber;
+ mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
+ {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
+#ifndef USE_HWC2
+ auto releaseFenceTime =
+ std::make_shared<FenceTime>(mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
+ mReleaseTimeline.updateSignalTimes();
+ mReleaseTimeline.push(releaseFenceTime);
+ if (mPreviousFrameNumber != 0) {
+ mFrameEventHistory.addRelease(mPreviousFrameNumber, latchTime,
+ std::move(releaseFenceTime));
+ }
+#endif
+ }
+
+ mRefreshPending = true;
+ mFrameLatencyNeeded = true;
+ if (oldActiveBuffer == NULL) {
+ // the first time we receive a buffer, we need to trigger a
+ // geometry invalidation.
+ recomputeVisibleRegions = true;
+ }
+
+ setDataSpace(mSurfaceFlingerConsumer->getCurrentDataSpace());
+
+ Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
+ const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
+ const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
+ if ((crop != mCurrentCrop) || (transform != mCurrentTransform) ||
+ (scalingMode != mCurrentScalingMode)) {
+ mCurrentCrop = crop;
+ mCurrentTransform = transform;
+ mCurrentScalingMode = scalingMode;
+ recomputeVisibleRegions = true;
+ }
+
+ if (oldActiveBuffer != NULL) {
+ uint32_t bufWidth = mActiveBuffer->getWidth();
+ uint32_t bufHeight = mActiveBuffer->getHeight();
+ if (bufWidth != uint32_t(oldActiveBuffer->width) ||
+ bufHeight != uint32_t(oldActiveBuffer->height)) {
+ recomputeVisibleRegions = true;
+ }
+ }
+
+ mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
+ if (oldOpacity != isOpaque(s)) {
+ recomputeVisibleRegions = true;
+ }
+
+ // Remove any sync points corresponding to the buffer which was just
+ // latched
+ {
+ Mutex::Autolock lock(mLocalSyncPointMutex);
+ auto point = mLocalSyncPoints.begin();
+ while (point != mLocalSyncPoints.end()) {
+ if (!(*point)->frameIsAvailable() || !(*point)->transactionIsApplied()) {
+ // This sync point must have been added since we started
+ // latching. Don't drop it yet.
+ ++point;
+ continue;
+ }
+
+ if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
+ point = mLocalSyncPoints.erase(point);
+ } else {
+ ++point;
+ }
+ }
+ }
+
+ // FIXME: postedRegion should be dirty & bounds
+ Region dirtyRegion(Rect(s.active.w, s.active.h));
+
+ // transform the dirty region to window-manager space
+ outDirtyRegion = (getTransform().transform(dirtyRegion));
+
+ return outDirtyRegion;
+}
+
+#ifdef USE_HWC2
+void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
+ // Apply this display's projection's viewport to the visible region
+ // before giving it to the HWC HAL.
+ const Transform& tr = displayDevice->getTransform();
+ const auto& viewport = displayDevice->getViewport();
+ Region visible = tr.transform(visibleRegion.intersect(viewport));
+ auto hwcId = displayDevice->getHwcDisplayId();
+ auto& hwcInfo = mHwcLayers[hwcId];
+ auto& hwcLayer = hwcInfo.layer;
+ auto error = hwcLayer->setVisibleRegion(visible);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ visible.dump(LOG_TAG);
+ }
+
+ error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ surfaceDamageRegion.dump(LOG_TAG);
+ }
+
+ // Sideband layers
+ if (mSidebandStream.get()) {
+ setCompositionType(hwcId, HWC2::Composition::Sideband);
+ ALOGV("[%s] Requesting Sideband composition", mName.string());
+ error = hwcLayer->setSidebandStream(mSidebandStream->handle());
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
+ mSidebandStream->handle(), to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+ return;
+ }
+
+ // Client layers
+ if (hwcInfo.forceClientComposition ||
+ (mActiveBuffer != nullptr && mActiveBuffer->handle == nullptr)) {
+ ALOGV("[%s] Requesting Client composition", mName.string());
+ setCompositionType(hwcId, HWC2::Composition::Client);
+ return;
+ }
+
+ // SolidColor layers
+ if (mActiveBuffer == nullptr) {
+ setCompositionType(hwcId, HWC2::Composition::SolidColor);
+
+ // For now, we only support black for DimLayer
+ error = hwcLayer->setColor({0, 0, 0, 255});
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ // Clear out the transform, because it doesn't make sense absent a
+ // source buffer
+ error = hwcLayer->setTransform(HWC2::Transform::None);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ return;
+ }
+
+ // Device or Cursor layers
+ if (mPotentialCursor) {
+ ALOGV("[%s] Requesting Cursor composition", mName.string());
+ setCompositionType(hwcId, HWC2::Composition::Cursor);
+ } else {
+ ALOGV("[%s] Requesting Device composition", mName.string());
+ setCompositionType(hwcId, HWC2::Composition::Device);
+ }
+
+ ALOGV("setPerFrameData: dataspace = %d", mCurrentState.dataSpace);
+ error = hwcLayer->setDataspace(mCurrentState.dataSpace);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentState.dataSpace,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ uint32_t hwcSlot = 0;
+ sp<GraphicBuffer> hwcBuffer;
+ hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer);
+
+ auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence();
+ error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
+ if (error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), mActiveBuffer->handle,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+}
+
+#else
+void BufferLayer::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);
+ layer.setSurfaceDamage(surfaceDamageRegion);
+ mIsGlesComposition = (layer.getCompositionType() == HWC_FRAMEBUFFER);
+
+ if (mSidebandStream.get()) {
+ layer.setSidebandStream(mSidebandStream);
+ } else {
+ // NOTE: buffer can be NULL if the client never drew into this
+ // layer yet, or if we ran out of memory
+ layer.setBuffer(mActiveBuffer);
+ }
+}
+#endif
+
+bool BufferLayer::isOpaque(const Layer::State& s) const
+{
+ // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
+ // layer's opaque flag.
+ if ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
+ return false;
+ }
+
+ // if the layer has the opaque flag, then we're always opaque,
+ // otherwise we use the current buffer's format.
+ return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
+}
+
+void BufferLayer::onFirstRef() {
+ // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer, true);
+ mProducer = new MonitoredProducer(producer, mFlinger, this);
+ mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName, this);
+ mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+ mSurfaceFlingerConsumer->setContentsChangedListener(this);
+ mSurfaceFlingerConsumer->setName(mName);
+
+ if (mFlinger->isLayerTripleBufferingDisabled()) {
+ mProducer->setMaxDequeuedBufferCount(2);
+ }
+
+ const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
+ updateTransformHint(hw);
+}
+
+// ---------------------------------------------------------------------------
+// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
+// ---------------------------------------------------------------------------
+
+void BufferLayer::onFrameAvailable(const BufferItem& item) {
+ // Add this buffer from our internal queue tracker
+ { // Autolock scope
+ Mutex::Autolock lock(mQueueItemLock);
+ mFlinger->mInterceptor.saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
+ item.mGraphicBuffer->getHeight(),
+ item.mFrameNumber);
+ // Reset the frame number tracker when we receive the first buffer after
+ // a frame number reset
+ if (item.mFrameNumber == 1) {
+ mLastFrameNumberReceived = 0;
+ }
+
+ // Ensure that callbacks are handled in order
+ while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+ status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
+ if (result != NO_ERROR) {
+ ALOGE("[%s] Timed out waiting on callback", mName.string());
+ }
+ }
+
+ mQueueItems.push_back(item);
+ android_atomic_inc(&mQueuedFrames);
+
+ // Wake up any pending callbacks
+ mLastFrameNumberReceived = item.mFrameNumber;
+ mQueueItemCondition.broadcast();
+ }
+
+ mFlinger->signalLayerUpdate();
+}
+
+void BufferLayer::onFrameReplaced(const BufferItem& item) {
+ { // Autolock scope
+ Mutex::Autolock lock(mQueueItemLock);
+
+ // Ensure that callbacks are handled in order
+ while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+ status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
+ if (result != NO_ERROR) {
+ ALOGE("[%s] Timed out waiting on callback", mName.string());
+ }
+ }
+
+ if (mQueueItems.empty()) {
+ ALOGE("Can't replace a frame on an empty queue");
+ return;
+ }
+ mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
+
+ // Wake up any pending callbacks
+ mLastFrameNumberReceived = item.mFrameNumber;
+ mQueueItemCondition.broadcast();
+ }
+}
+
+void BufferLayer::onSidebandStreamChanged() {
+ if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
+ // mSidebandStreamChanged was false
+ mFlinger->signalLayerUpdate();
+ }
+}
+
+bool BufferLayer::needsFiltering(const RenderArea& renderArea) const {
+ return mNeedsFiltering || renderArea.needsFiltering();
+}
+
+// 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
+// TODO: move definition for device-specific range into
+// hardware.h, instead of using hard-coded values here.
+#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
+
+bool BufferLayer::getOpacityForFormat(uint32_t format) {
+ if (HARDWARE_IS_DEVICE_FORMAT(format)) {
+ return true;
+ }
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
+ return false;
+ }
+ // in all other case, we have no blending (also for unknown formats)
+ return true;
+}
+
+void BufferLayer::drawWithOpenGL(const RenderArea& renderArea,
+ bool useIdentityTransform) const {
+ const State& s(getDrawingState());
+
+ computeGeometry(renderArea, mMesh, useIdentityTransform);
+
+ /*
+ * 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 whether 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.
+ */
+ Rect win(computeBounds());
+
+ Transform t = getTransform();
+ if (!s.finalCrop.isEmpty()) {
+ win = t.transform(win);
+ if (!win.intersect(s.finalCrop, &win)) {
+ win.clear();
+ }
+ win = t.inverse().transform(win);
+ if (!win.intersect(computeBounds(), &win)) {
+ win.clear();
+ }
+ }
+
+ float left = float(win.left) / float(s.active.w);
+ float top = float(win.top) / float(s.active.h);
+ float right = float(win.right) / float(s.active.w);
+ float bottom = float(win.bottom) / float(s.active.h);
+
+ // TODO: we probably want to generate the texture coords with the mesh
+ // here we assume that we only have 4 vertices
+ Mesh::VertexArray<vec2> texCoords(mMesh.getTexCoordArray<vec2>());
+ texCoords[0] = vec2(left, 1.0f - top);
+ texCoords[1] = vec2(left, 1.0f - bottom);
+ texCoords[2] = vec2(right, 1.0f - bottom);
+ texCoords[3] = vec2(right, 1.0f - top);
+
+ RenderEngine& engine(mFlinger->getRenderEngine());
+ engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), false /* disableTexture */,
+ getColor());
+#ifdef USE_HWC2
+ engine.setSourceDataSpace(mCurrentState.dataSpace);
+#endif
+ engine.drawMesh(mMesh);
+ engine.disableBlending();
+}
+
+uint32_t BufferLayer::getProducerStickyTransform() const {
+ int producerStickyTransform = 0;
+ int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform);
+ if (ret != OK) {
+ ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__,
+ strerror(-ret), ret);
+ return 0;
+ }
+ return static_cast<uint32_t>(producerStickyTransform);
+}
+
+bool BufferLayer::latchUnsignaledBuffers() {
+ static bool propertyLoaded = false;
+ static bool latch = false;
+ static std::mutex mutex;
+ std::lock_guard<std::mutex> lock(mutex);
+ if (!propertyLoaded) {
+ char value[PROPERTY_VALUE_MAX] = {};
+ property_get("debug.sf.latch_unsignaled", value, "0");
+ latch = atoi(value);
+ propertyLoaded = true;
+ }
+ return latch;
+}
+
+uint64_t BufferLayer::getHeadFrameNumber() const {
+ Mutex::Autolock lock(mQueueItemLock);
+ if (!mQueueItems.empty()) {
+ return mQueueItems[0].mFrameNumber;
+ } else {
+ return mCurrentFrameNumber;
+ }
+}
+
+bool BufferLayer::headFenceHasSignaled() const {
+#ifdef USE_HWC2
+ if (latchUnsignaledBuffers()) {
+ return true;
+ }
+
+ Mutex::Autolock lock(mQueueItemLock);
+ if (mQueueItems.empty()) {
+ return true;
+ }
+ if (mQueueItems[0].mIsDroppable) {
+ // Even though this buffer's fence may not have signaled yet, it could
+ // be replaced by another buffer before it has a chance to, which means
+ // that it's possible to get into a situation where a buffer is never
+ // able to be latched. To avoid this, grab this buffer anyway.
+ return true;
+ }
+ return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+#else
+ return true;
+#endif
+}
+
+uint32_t BufferLayer::getEffectiveScalingMode() const {
+ if (mOverrideScalingMode >= 0) {
+ return mOverrideScalingMode;
+ }
+ return mCurrentScalingMode;
+}
+
+// ----------------------------------------------------------------------------
+// transaction
+// ----------------------------------------------------------------------------
+
+void BufferLayer::notifyAvailableFrames() {
+ auto headFrameNumber = getHeadFrameNumber();
+ bool headFenceSignaled = headFenceHasSignaled();
+ Mutex::Autolock lock(mLocalSyncPointMutex);
+ for (auto& point : mLocalSyncPoints) {
+ if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
+ point->setFrameAvailable();
+ }
+ }
+}
+
+sp<IGraphicBufferProducer> BufferLayer::getProducer() const {
+ return mProducer;
+}
+
+// ---------------------------------------------------------------------------
+// h/w composer set-up
+// ---------------------------------------------------------------------------
+
+bool BufferLayer::allTransactionsSignaled() {
+ auto headFrameNumber = getHeadFrameNumber();
+ bool matchingFramesFound = false;
+ bool allTransactionsApplied = true;
+ Mutex::Autolock lock(mLocalSyncPointMutex);
+
+ for (auto& point : mLocalSyncPoints) {
+ if (point->getFrameNumber() > headFrameNumber) {
+ break;
+ }
+ matchingFramesFound = true;
+
+ if (!point->frameIsAvailable()) {
+ // We haven't notified the remote layer that the frame for
+ // this point is available yet. Notify it now, and then
+ // abort this attempt to latch.
+ point->setFrameAvailable();
+ allTransactionsApplied = false;
+ break;
+ }
+
+ allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied();
+ }
+ return !matchingFramesFound || allTransactionsApplied;
+}
+
+} // namespace android
+
+#if defined(__gl_h_)
+#error "don't include gl/gl.h in this file"
+#endif
+
+#if defined(__gl2_h_)
+#error "don't include gl2/gl2.h in this file"
+#endif
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
new file mode 100644
index 0000000..b245f29
--- /dev/null
+++ b/services/surfaceflinger/BufferLayer.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include "Layer.h"
+#include "Client.h"
+#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/HWComposerBufferCache.h"
+#include "FrameTracker.h"
+#include "LayerVector.h"
+#include "MonitoredProducer.h"
+#include "RenderEngine/Mesh.h"
+#include "RenderEngine/Texture.h"
+#include "SurfaceFlinger.h"
+#include "SurfaceFlingerConsumer.h"
+#include "Transform.h"
+
+#include <gui/ISurfaceComposerClient.h>
+#include <gui/LayerState.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <ui/FrameStats.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
+#include <ui/Region.h>
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <list>
+
+namespace android {
+
+/*
+ * A new BufferQueue and a new SurfaceFlingerConsumer are created when the
+ * BufferLayer is first referenced.
+ *
+ * This also implements onFrameAvailable(), which notifies SurfaceFlinger
+ * that new data has arrived.
+ */
+class BufferLayer : public Layer, public SurfaceFlingerConsumer::ContentsChangedListener {
+public:
+ BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
+ uint32_t h, uint32_t flags);
+
+ ~BufferLayer() override;
+
+ // -----------------------------------------------------------------------
+ // Overriden from Layer
+ // -----------------------------------------------------------------------
+
+ /*
+ * getTypeId - Provide unique string for each class type in the Layer
+ * hierarchy
+ */
+ const char* getTypeId() const override { return "BufferLayer"; }
+
+ /*
+ * isProtected - true if the layer may contain protected content in the
+ * GRALLOC_USAGE_PROTECTED sense.
+ */
+ bool isProtected() const;
+
+ /*
+ * isVisible - true if this layer is visible, false otherwise
+ */
+ bool isVisible() const override;
+
+ /*
+ * isFixedSize - true if content has a fixed size
+ */
+ bool isFixedSize() const override;
+
+ // the this layer's size and format
+ status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+
+ /*
+ * onDraw - draws the surface.
+ */
+ void onDraw(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform) const override;
+
+ bool onPreComposition(nsecs_t refreshStartTime) override;
+
+#ifdef USE_HWC2
+ // If a buffer was replaced this frame, release the former buffer
+ void releasePendingBuffer(nsecs_t dequeueReadyTime);
+#endif
+
+ /*
+ * 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.
+ */
+ Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+ bool isBufferLatched() const override { return mRefreshPending; }
+
+#ifdef USE_HWC2
+ void setPerFrameData(const sp<const DisplayDevice>& displayDevice);
+#else
+ void setPerFrameData(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer);
+#endif
+ bool isOpaque(const Layer::State& s) const override;
+
+private:
+ void onFirstRef() override;
+
+ // Interface implementation for
+ // SurfaceFlingerConsumer::ContentsChangedListener
+ void onFrameAvailable(const BufferItem& item) override;
+ void onFrameReplaced(const BufferItem& item) override;
+ void onSidebandStreamChanged() override;
+
+ // needsLinearFiltering - true if this surface's state requires filtering
+ bool needsFiltering(const RenderArea& renderArea) const;
+
+ static bool getOpacityForFormat(uint32_t format);
+
+ // drawing
+ void drawWithOpenGL(const RenderArea& renderArea,
+ bool useIdentityTransform) const;
+
+ // Temporary - Used only for LEGACY camera mode.
+ uint32_t getProducerStickyTransform() const;
+
+ // Loads the corresponding system property once per process
+ static bool latchUnsignaledBuffers();
+
+ uint64_t getHeadFrameNumber() const;
+ bool headFenceHasSignaled() const;
+
+ // Returns the current scaling mode, unless mOverrideScalingMode
+ // is set, in which case, it returns mOverrideScalingMode
+ uint32_t getEffectiveScalingMode() const override;
+
+public:
+ void notifyAvailableFrames() override;
+
+ PixelFormat getPixelFormat() const override { return mFormat; }
+ sp<IGraphicBufferProducer> getProducer() const;
+
+private:
+ // Check all of the local sync points to ensure that all transactions
+ // which need to have been applied prior to the frame which is about to
+ // be latched have signaled
+ bool allTransactionsSignaled();
+ sp<IGraphicBufferProducer> mProducer;
+
+ // constants
+ uint32_t mTextureName; // from GLES
+ PixelFormat mFormat;
+
+ // main thread
+ uint32_t mCurrentScalingMode;
+ bool mBufferLatched = false; // TODO: Use mActiveBuffer?
+ uint64_t mPreviousFrameNumber; // Only accessed on the main thread.
+ // The texture used to draw the layer in GLES composition mode
+ mutable Texture mTexture;
+
+ bool mUpdateTexImageFailed; // This is only accessed on the main thread.
+ bool mRefreshPending;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 32526dd..72fdaaa 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -37,7 +37,10 @@
ColorLayer::ColorLayer(SurfaceFlinger* flinger, const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags)
- : Layer(flinger, client, name, w, h, flags) {
+ : Layer(flinger, client, name, w, h, flags) {
+
+ // drawing state & current state are identical
+ mDrawingState = mCurrentState;
}
void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */,
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index cdf3eca..c68ad02 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -26,8 +26,7 @@
namespace android {
-class ColorLayer : public Layer
-{
+class ColorLayer : public Layer {
public:
ColorLayer(SurfaceFlinger* flinger, const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags);
@@ -36,10 +35,19 @@
virtual const char* getTypeId() const { return "ColorLayer"; }
virtual void onDraw(const RenderArea& renderArea, const Region& clip,
bool useIdentityTransform) const;
+ bool isVisible() const override;
virtual bool isOpaque(const Layer::State&) const { return false; }
- virtual bool isSecure() const { return false; }
virtual bool isFixedSize() const { return true; }
- virtual bool isVisible() const;
+
+ void notifyAvailableFrames() override {}
+ PixelFormat getPixelFormat() const override { return PIXEL_FORMAT_NONE; }
+ uint32_t getEffectiveScalingMode() const override { return 0; }
+#ifdef USE_HWC2
+ void releasePendingBuffer(nsecs_t) override {}
+#endif
+ Region latchBuffer(bool&, nsecs_t) override { return Region(); }
+ bool isBufferLatched() const override { return false; }
+ bool onPreComposition(nsecs_t) override { return true; }
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 0525607..763488c 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -62,19 +62,16 @@
namespace android {
-// ---------------------------------------------------------------------------
-
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),
+ : contentDirty(false),
sequence(uint32_t(android_atomic_inc(&sSequence))),
mFlinger(flinger),
- mTextureName(UINT32_MAX),
+ mSurfaceFlingerConsumer(NULL),
mPremultipliedAlpha(true),
- mName("unnamed"),
- mFormat(PIXEL_FORMAT_NONE),
+ mName(name),
mTransactionFlags(0),
mPendingStateMutex(),
mPendingStates(),
@@ -82,13 +79,9 @@
mSidebandStreamChanged(false),
mActiveBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
mCurrentTransform(0),
- mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mOverrideScalingMode(-1),
mCurrentOpacity(true),
- mBufferLatched(false),
mCurrentFrameNumber(0),
- mPreviousFrameNumber(0),
- mRefreshPending(false),
mFrameLatencyNeeded(false),
mFiltering(false),
mNeedsFiltering(false),
@@ -97,24 +90,17 @@
mIsGlesComposition(false),
#endif
mProtectedByApp(false),
- mHasSurface(false),
mClientRef(client),
mPotentialCursor(false),
mQueueItemLock(),
mQueueItemCondition(),
mQueueItems(),
mLastFrameNumberReceived(0),
- mUpdateTexImageFailed(false),
mAutoRefresh(false),
mFreezeGeometryUpdates(false)
{
-#ifdef USE_HWC2
- ALOGV("Creating Layer %s", name.string());
-#endif
mCurrentCrop.makeInvalid();
- mFlinger->getRenderEngine().genTextures(1, &mTextureName);
- mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);
uint32_t layerFlags = 0;
if (flags & ISurfaceComposerClient::eHidden)
@@ -124,14 +110,12 @@
if (flags & ISurfaceComposerClient::eSecure)
layerFlags |= layer_state_t::eLayerSecure;
- if (flags & ISurfaceComposerClient::eNonPremultiplied)
- mPremultipliedAlpha = false;
-
mName = name;
mTransactionName = String8("TX - ") + mName;
mCurrentState.active.w = w;
mCurrentState.active.h = h;
+ mCurrentState.flags = layerFlags;
mCurrentState.active.transform.set(0, 0);
mCurrentState.crop.makeInvalid();
mCurrentState.finalCrop.makeInvalid();
@@ -140,7 +124,6 @@
mCurrentState.z = 0;
mCurrentState.color.a = 1.0f;
mCurrentState.layerStack = 0;
- mCurrentState.flags = layerFlags;
mCurrentState.sequence = 0;
mCurrentState.requested = mCurrentState.active;
mCurrentState.dataSpace = HAL_DATASPACE_UNKNOWN;
@@ -166,46 +149,10 @@
}
void Layer::onFirstRef() {
- // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer, true);
- mProducer = new MonitoredProducer(producer, mFlinger, this);
- mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName, this);
- mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
- mSurfaceFlingerConsumer->setContentsChangedListener(this);
- mSurfaceFlingerConsumer->setName(mName);
-
- if (mFlinger->isLayerTripleBufferingDisabled()) {
- mProducer->setMaxDequeuedBufferCount(2);
- }
-
- const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
- updateTransformHint(hw);
}
Layer::~Layer() {
- sp<Client> c(mClientRef.promote());
- if (c != 0) {
- c->detachLayer(this);
- }
-
- for (auto& point : mRemoteSyncPoints) {
- point->setTransactionApplied();
- }
- for (auto& point : mLocalSyncPoints) {
- point->setFrameAvailable();
- }
- mFlinger->deleteTextureAsync(mTextureName);
mFrameTracker.logAndResetStats(mName);
-
-#ifdef USE_HWC2
- if (!mHwcLayers.empty()) {
- ALOGE("Found stale hardware composer layers when destroying "
- "surface flinger layer %s", mName.string());
- destroyAllHwcLayers();
- }
-#endif
}
// ---------------------------------------------------------------------------
@@ -217,7 +164,9 @@
if (mHwcLayers.empty()) {
return;
}
- mSurfaceFlingerConsumer->setReleaseFence(releaseFence);
+ if (mSurfaceFlingerConsumer) {
+ mSurfaceFlingerConsumer->setReleaseFence(releaseFence);
+ }
}
#else
void Layer::onLayerDisplayed(const sp<const DisplayDevice>& /* hw */,
@@ -229,70 +178,6 @@
}
#endif
-void Layer::onFrameAvailable(const BufferItem& item) {
- // Add this buffer from our internal queue tracker
- { // Autolock scope
- Mutex::Autolock lock(mQueueItemLock);
- mFlinger->mInterceptor.saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
- item.mGraphicBuffer->getHeight(), item.mFrameNumber);
- // Reset the frame number tracker when we receive the first buffer after
- // a frame number reset
- if (item.mFrameNumber == 1) {
- mLastFrameNumberReceived = 0;
- }
-
- // Ensure that callbacks are handled in order
- while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
- status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
- ms2ns(500));
- if (result != NO_ERROR) {
- ALOGE("[%s] Timed out waiting on callback", mName.string());
- }
- }
-
- mQueueItems.push_back(item);
- android_atomic_inc(&mQueuedFrames);
-
- // Wake up any pending callbacks
- mLastFrameNumberReceived = item.mFrameNumber;
- mQueueItemCondition.broadcast();
- }
-
- mFlinger->signalLayerUpdate();
-}
-
-void Layer::onFrameReplaced(const BufferItem& item) {
- { // Autolock scope
- Mutex::Autolock lock(mQueueItemLock);
-
- // Ensure that callbacks are handled in order
- while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
- status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
- ms2ns(500));
- if (result != NO_ERROR) {
- ALOGE("[%s] Timed out waiting on callback", mName.string());
- }
- }
-
- if (mQueueItems.empty()) {
- ALOGE("Can't replace a frame on an empty queue");
- return;
- }
- mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
-
- // Wake up any pending callbacks
- mLastFrameNumberReceived = item.mFrameNumber;
- mQueueItemCondition.broadcast();
- }
-}
-
-void Layer::onSidebandStreamChanged() {
- if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
- // mSidebandStreamChanged was false
- mFlinger->signalLayerUpdate();
- }
-}
-
void Layer::onRemovedFromCurrentState() {
// the layer is removed from SF mCurrentState to mLayersPendingRemoval
@@ -313,7 +198,9 @@
void Layer::onRemoved() {
// the layer is removed from SF mLayersPendingRemoval
- mSurfaceFlingerConsumer->abandon();
+ if (mSurfaceFlingerConsumer) {
+ mSurfaceFlingerConsumer->abandon();
+ }
#ifdef USE_HWC2
destroyAllHwcLayers();
#endif
@@ -335,47 +222,11 @@
return mPremultipliedAlpha;
}
-status_t Layer::setBuffers( uint32_t w, uint32_t h,
- PixelFormat format, uint32_t flags)
-{
- uint32_t const maxSurfaceDims = min(
- mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims());
-
- // never allow a surface larger than what our underlying GL implementation
- // can handle.
- if ((uint32_t(w)>maxSurfaceDims) || (uint32_t(h)>maxSurfaceDims)) {
- ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
- return BAD_VALUE;
- }
-
- mFormat = format;
-
- mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
- mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
- mCurrentOpacity = getOpacityForFormat(format);
-
- mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
- mSurfaceFlingerConsumer->setDefaultBufferFormat(format);
- mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
-
- return NO_ERROR;
-}
-
sp<IBinder> Layer::getHandle() {
Mutex::Autolock _l(mLock);
-
- LOG_ALWAYS_FATAL_IF(mHasSurface,
- "Layer::getHandle() has already been called");
-
- mHasSurface = true;
-
return new Handle(mFlinger, this);
}
-sp<IGraphicBufferProducer> Layer::getProducer() const {
- return mProducer;
-}
-
// ---------------------------------------------------------------------------
// h/w composer set-up
// ---------------------------------------------------------------------------
@@ -1077,125 +928,6 @@
onDraw(renderArea, Region(renderArea.getBounds()), false);
}
-static constexpr mat4 inverseOrientation(uint32_t transform) {
- const mat4 flipH(-1,0,0,0, 0,1,0,0, 0,0,1,0, 1,0,0,1);
- const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1);
- const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1);
- mat4 tr;
-
- if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
- tr = tr * rot90;
- }
- if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
- tr = tr * flipH;
- }
- if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
- tr = tr * flipV;
- }
- return inverse(tr);
-}
-
-/*
- * onDraw will draw the current layer onto the presentable buffer
- */
-void Layer::onDraw(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform) const
-{
- ATRACE_CALL();
-
- if (CC_UNLIKELY(mActiveBuffer == 0)) {
- // the texture has not been created yet, this Layer has
- // in fact never been drawn into. This happens frequently with
- // SurfaceView because the WindowManager can't know when the client
- // has drawn the first time.
-
- // If there is nothing under us, we paint the screen in black, otherwise
- // we just skip this update.
-
- // figure out if there is something below us
- Region under;
- bool finished = false;
- mFlinger->mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (finished || layer == static_cast<Layer const*>(this)) {
- finished = true;
- return;
- }
- under.orSelf(renderArea.getTransform().transform(layer->visibleRegion));
- });
- // if not everything below us is covered, we plug the holes!
- Region holes(clip.subtract(under));
- if (!holes.isEmpty()) {
- clearWithOpenGL(renderArea, 0, 0, 0, 1);
- }
- return;
- }
-
- // 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.
- }
-
- bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure());
-
- RenderEngine& engine(mFlinger->getRenderEngine());
-
- if (!blackOutLayer) {
- // TODO: we could be more subtle with isFixedSize()
- const bool useFiltering = getFiltering() || needsFiltering(renderArea) || isFixedSize();
-
- // Query the texture matrix given our current filtering mode.
- float textureMatrix[16];
- mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
- mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
-
- if (getTransformToDisplayInverse()) {
-
- /*
- * the code below applies the primary display's inverse transform to
- * the texture transform
- */
- uint32_t transform =
- DisplayDevice::getPrimaryDisplayOrientationTransform();
- mat4 tr = inverseOrientation(transform);
-
- /**
- * TODO(b/36727915): This is basically a hack.
- *
- * Ensure that regardless of the parent transformation,
- * this buffer is always transformed from native display
- * orientation to display orientation. For example, in the case
- * of a camera where the buffer remains in native orientation,
- * we want the pixels to always be upright.
- */
- sp<Layer> p = mDrawingParent.promote();
- if (p != nullptr) {
- const auto parentTransform = p->getTransform();
- tr = tr * inverseOrientation(parentTransform.getOrientation());
- }
-
- // and finally apply it to the original texture matrix
- const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
- memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
- }
-
- // Set things up for texturing.
- mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
- mTexture.setFiltering(useFiltering);
- mTexture.setMatrix(textureMatrix);
-
- engine.setupLayerTexturing(mTexture);
- } else {
- engine.setupLayerBlackedOut();
- }
- drawWithOpenGL(renderArea, useIdentityTransform);
- engine.disableTexturing();
-}
-
-
void Layer::clearWithOpenGL(const RenderArea& renderArea,
float red, float green, float blue,
float alpha) const
@@ -1210,62 +942,6 @@
clearWithOpenGL(renderArea, 0,0,0,0);
}
-void Layer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
- const State& s(getDrawingState());
-
- computeGeometry(renderArea, mMesh, useIdentityTransform);
-
- /*
- * 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 whether 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.
- */
- Rect win(computeBounds());
-
- Transform t = getTransform();
- if (!s.finalCrop.isEmpty()) {
- win = t.transform(win);
- if (!win.intersect(s.finalCrop, &win)) {
- win.clear();
- }
- win = t.inverse().transform(win);
- if (!win.intersect(computeBounds(), &win)) {
- win.clear();
- }
- }
-
- float left = float(win.left) / float(s.active.w);
- float top = float(win.top) / float(s.active.h);
- float right = float(win.right) / float(s.active.w);
- float bottom = float(win.bottom) / float(s.active.h);
-
- // TODO: we probably want to generate the texture coords with the mesh
- // here we assume that we only have 4 vertices
- Mesh::VertexArray<vec2> texCoords(mMesh.getTexCoordArray<vec2>());
- texCoords[0] = vec2(left, 1.0f - top);
- texCoords[1] = vec2(left, 1.0f - bottom);
- texCoords[2] = vec2(right, 1.0f - bottom);
- texCoords[3] = vec2(right, 1.0f - top);
-
- RenderEngine& engine(mFlinger->getRenderEngine());
- engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s),
- false /* disableTexture */, getColor());
-#ifdef USE_HWC2
- engine.setSourceDataSpace(mCurrentState.dataSpace);
-#endif
- engine.drawMesh(mMesh);
- engine.disableBlending();
-}
-
#ifdef USE_HWC2
void Layer::setCompositionType(int32_t hwcId, HWC2::Composition type,
bool callIntoHwc) {
@@ -1320,64 +996,6 @@
}
#endif
-uint32_t Layer::getProducerStickyTransform() const {
- int producerStickyTransform = 0;
- int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform);
- if (ret != OK) {
- ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__,
- strerror(-ret), ret);
- return 0;
- }
- return static_cast<uint32_t>(producerStickyTransform);
-}
-
-bool Layer::latchUnsignaledBuffers() {
- static bool propertyLoaded = false;
- static bool latch = false;
- static std::mutex mutex;
- std::lock_guard<std::mutex> lock(mutex);
- if (!propertyLoaded) {
- char value[PROPERTY_VALUE_MAX] = {};
- property_get("debug.sf.latch_unsignaled", value, "0");
- latch = atoi(value);
- propertyLoaded = true;
- }
- return latch;
-}
-
-uint64_t Layer::getHeadFrameNumber() const {
- Mutex::Autolock lock(mQueueItemLock);
- if (!mQueueItems.empty()) {
- return mQueueItems[0].mFrameNumber;
- } else {
- return mCurrentFrameNumber;
- }
-}
-
-bool Layer::headFenceHasSignaled() const {
-#ifdef USE_HWC2
- if (latchUnsignaledBuffers()) {
- return true;
- }
-
- Mutex::Autolock lock(mQueueItemLock);
- if (mQueueItems.empty()) {
- return true;
- }
- if (mQueueItems[0].mIsDroppable) {
- // Even though this buffer's fence may not have signaled yet, it could
- // be replaced by another buffer before it has a chance to, which means
- // that it's possible to get into a situation where a buffer is never
- // able to be latched. To avoid this, grab this buffer anyway.
- return true;
- }
- return mQueueItems[0].mFenceTime->getSignalTime() !=
- Fence::SIGNAL_TIME_PENDING;
-#else
- return true;
-#endif
-}
-
bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) {
if (point->getFrameNumber() <= mCurrentFrameNumber) {
// Don't bother with a SyncPoint, since we've already latched the
@@ -1398,28 +1016,6 @@
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
-// TODO: move definition for device-specific range into
-// hardware.h, instead of using hard-coded values here.
-#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
-
-bool Layer::getOpacityForFormat(uint32_t format) {
- if (HARDWARE_IS_DEVICE_FORMAT(format)) {
- return true;
- }
- switch (format) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_BGRA_8888:
- case HAL_PIXEL_FORMAT_RGBA_FP16:
- case HAL_PIXEL_FORMAT_RGBA_1010102:
- return false;
- }
- // in all other case, we have no blending (also for unknown formats)
- return true;
-}
-
// ----------------------------------------------------------------------------
// local state
// ----------------------------------------------------------------------------
@@ -1476,44 +1072,12 @@
}
}
-bool Layer::isOpaque(const Layer::State& s) const
-{
- // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
- // layer's opaque flag.
- if ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
- return false;
- }
-
- // if the layer has the opaque flag, then we're always opaque,
- // otherwise we use the current buffer's format.
- return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
-}
-
bool Layer::isSecure() const
{
const Layer::State& s(mDrawingState);
return (s.flags & layer_state_t::eLayerSecure);
}
-bool Layer::isProtected() const
-{
- const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
- return (activeBuffer != 0) &&
- (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
-}
-
-bool Layer::isFixedSize() const {
- return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE;
-}
-
-bool Layer::isCropped() const {
- return !mCurrentCrop.isEmpty();
-}
-
-bool Layer::needsFiltering(const RenderArea& renderArea) const {
- return mNeedsFiltering || renderArea.needsFiltering();
-}
-
void Layer::setVisibleRegion(const Region& visibleRegion) {
// always called from main thread
this->visibleRegion = visibleRegion;
@@ -1632,17 +1196,6 @@
return stateUpdateAvailable;
}
-void Layer::notifyAvailableFrames() {
- auto headFrameNumber = getHeadFrameNumber();
- bool headFenceSignaled = headFenceHasSignaled();
- Mutex::Autolock lock(mLocalSyncPointMutex);
- for (auto& point : mLocalSyncPoints) {
- if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
- point->setFrameAvailable();
- }
- }
-}
-
uint32_t Layer::doTransaction(uint32_t flags) {
ATRACE_CALL();
@@ -1657,7 +1210,7 @@
const bool sizeChanged = (c.requested.w != s.requested.w) ||
(c.requested.h != s.requested.h);
- if (sizeChanged) {
+ if (mSurfaceFlingerConsumer && sizeChanged) {
// the size changed, we need to ask our client to request a new buffer
ALOGD_IF(DEBUG_RESIZE,
"doTransaction: geometry (layer=%p '%s'), tr=%02x, scalingMode=%d\n"
@@ -1984,13 +1537,6 @@
setTransactionFlags(eTransactionNeeded);
}
-uint32_t Layer::getEffectiveScalingMode() const {
- if (mOverrideScalingMode >= 0) {
- return mOverrideScalingMode;
- }
- return mCurrentScalingMode;
-}
-
bool Layer::setLayerStack(uint32_t layerStack) {
if (mCurrentState.layerStack == layerStack)
return false;
@@ -2081,15 +1627,6 @@
return isDue || !isPlausible;
}
-bool Layer::onPreComposition(nsecs_t refreshStartTime) {
- if (mBufferLatched) {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
- }
- mRefreshPending = false;
- return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
-}
-
bool Layer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
const CompositorTiming& compositorTiming) {
@@ -2135,25 +1672,6 @@
return true;
}
-#ifdef USE_HWC2
-void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
- if (!mSurfaceFlingerConsumer->releasePendingBuffer()) {
- return;
- }
-
- auto releaseFenceTime = std::make_shared<FenceTime>(
- mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
- mReleaseTimeline.updateSignalTimes();
- mReleaseTimeline.push(releaseFenceTime);
-
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- if (mPreviousFrameNumber != 0) {
- mFrameEventHistory.addRelease(mPreviousFrameNumber,
- dequeueReadyTime, std::move(releaseFenceTime));
- }
-}
-#endif
-
bool Layer::isHiddenByPolicy() const {
const Layer::State& s(mDrawingState);
const auto& parent = mDrawingParent.promote();
@@ -2163,249 +1681,6 @@
return s.flags & layer_state_t::eLayerHidden;
}
-bool Layer::isVisible() const {
- return !(isHiddenByPolicy()) && getAlpha() > 0.0f
- && (mActiveBuffer != NULL || mSidebandStream != NULL);
-}
-
-bool Layer::allTransactionsSignaled() {
- auto headFrameNumber = getHeadFrameNumber();
- bool matchingFramesFound = false;
- bool allTransactionsApplied = true;
- Mutex::Autolock lock(mLocalSyncPointMutex);
-
- for (auto& point : mLocalSyncPoints) {
- if (point->getFrameNumber() > headFrameNumber) {
- break;
- }
- matchingFramesFound = true;
-
- if (!point->frameIsAvailable()) {
- // We haven't notified the remote layer that the frame for
- // this point is available yet. Notify it now, and then
- // abort this attempt to latch.
- point->setFrameAvailable();
- allTransactionsApplied = false;
- break;
- }
-
- allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied();
- }
- return !matchingFramesFound || allTransactionsApplied;
-}
-
-Region Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime)
-{
- ATRACE_CALL();
-
- if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
- // mSidebandStreamChanged was true
- mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
- if (mSidebandStream != NULL) {
- setTransactionFlags(eTransactionNeeded);
- mFlinger->setTransactionFlags(eTraversalNeeded);
- }
- recomputeVisibleRegions = true;
-
- const State& s(getDrawingState());
- return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
- }
-
- Region outDirtyRegion;
- if (mQueuedFrames <= 0 && !mAutoRefresh) {
- return outDirtyRegion;
- }
-
- // if we've already called updateTexImage() without going through
- // a composition step, we have to skip this layer at this point
- // because we cannot call updateTeximage() without a corresponding
- // compositionComplete() call.
- // we'll trigger an update in onPreComposition().
- if (mRefreshPending) {
- return outDirtyRegion;
- }
-
- // If the head buffer's acquire fence hasn't signaled yet, return and
- // try again later
- if (!headFenceHasSignaled()) {
- mFlinger->signalLayerUpdate();
- return outDirtyRegion;
- }
-
- // Capture the old state of the layer for comparisons later
- const State& s(getDrawingState());
- const bool oldOpacity = isOpaque(s);
- sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
-
- if (!allTransactionsSignaled()) {
- mFlinger->signalLayerUpdate();
- return outDirtyRegion;
- }
-
- // This boolean is used to make sure that SurfaceFlinger's shadow copy
- // of the buffer queue isn't modified when the buffer queue is returning
- // BufferItem's that weren't actually queued. This can happen in shared
- // buffer mode.
- bool queuedBuffer = false;
- LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
- getProducerStickyTransform() != 0, mName.string(),
- mOverrideScalingMode, mFreezeGeometryUpdates);
- status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
- mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
- mLastFrameNumberReceived);
- if (updateResult == BufferQueue::PRESENT_LATER) {
- // Producer doesn't want buffer to be displayed yet. Signal a
- // layer update so we check again at the next opportunity.
- mFlinger->signalLayerUpdate();
- return outDirtyRegion;
- } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
- // If the buffer has been rejected, remove it from the shadow queue
- // and return early
- if (queuedBuffer) {
- Mutex::Autolock lock(mQueueItemLock);
- mQueueItems.removeAt(0);
- android_atomic_dec(&mQueuedFrames);
- }
- return outDirtyRegion;
- } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
- // This can occur if something goes wrong when trying to create the
- // EGLImage for this buffer. If this happens, the buffer has already
- // been released, so we need to clean up the queue and bug out
- // early.
- if (queuedBuffer) {
- Mutex::Autolock lock(mQueueItemLock);
- mQueueItems.clear();
- android_atomic_and(0, &mQueuedFrames);
- }
-
- // Once we have hit this state, the shadow queue may no longer
- // correctly reflect the incoming BufferQueue's contents, so even if
- // updateTexImage starts working, the only safe course of action is
- // to continue to ignore updates.
- mUpdateTexImageFailed = true;
-
- return outDirtyRegion;
- }
-
- if (queuedBuffer) {
- // Autolock scope
- auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
-
- Mutex::Autolock lock(mQueueItemLock);
-
- // Remove any stale buffers that have been dropped during
- // updateTexImage
- while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
- mQueueItems.removeAt(0);
- android_atomic_dec(&mQueuedFrames);
- }
-
- mQueueItems.removeAt(0);
- }
-
-
- // Decrement the queued-frames count. Signal another event if we
- // have more frames pending.
- if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1)
- || mAutoRefresh) {
- mFlinger->signalLayerUpdate();
- }
-
- // update the active buffer
- mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer(
- &mActiveBufferSlot);
- if (mActiveBuffer == NULL) {
- // this can only happen if the very first buffer was rejected.
- return outDirtyRegion;
- }
-
- mBufferLatched = true;
- mPreviousFrameNumber = mCurrentFrameNumber;
- mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
-
- {
- Mutex::Autolock lock(mFrameEventHistoryMutex);
- mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
-#ifndef USE_HWC2
- auto releaseFenceTime = std::make_shared<FenceTime>(
- mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
- mReleaseTimeline.updateSignalTimes();
- mReleaseTimeline.push(releaseFenceTime);
- if (mPreviousFrameNumber != 0) {
- mFrameEventHistory.addRelease(mPreviousFrameNumber,
- latchTime, std::move(releaseFenceTime));
- }
-#endif
- }
-
- mRefreshPending = true;
- mFrameLatencyNeeded = true;
- if (oldActiveBuffer == NULL) {
- // the first time we receive a buffer, we need to trigger a
- // geometry invalidation.
- recomputeVisibleRegions = true;
- }
-
- setDataSpace(mSurfaceFlingerConsumer->getCurrentDataSpace());
-
- Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
- const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
- const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
- if ((crop != mCurrentCrop) ||
- (transform != mCurrentTransform) ||
- (scalingMode != mCurrentScalingMode))
- {
- mCurrentCrop = crop;
- mCurrentTransform = transform;
- mCurrentScalingMode = scalingMode;
- recomputeVisibleRegions = true;
- }
-
- if (oldActiveBuffer != NULL) {
- uint32_t bufWidth = mActiveBuffer->getWidth();
- uint32_t bufHeight = mActiveBuffer->getHeight();
- if (bufWidth != uint32_t(oldActiveBuffer->width) ||
- bufHeight != uint32_t(oldActiveBuffer->height)) {
- recomputeVisibleRegions = true;
- }
- }
-
- mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
- if (oldOpacity != isOpaque(s)) {
- recomputeVisibleRegions = true;
- }
-
- // Remove any sync points corresponding to the buffer which was just
- // latched
- {
- Mutex::Autolock lock(mLocalSyncPointMutex);
- auto point = mLocalSyncPoints.begin();
- while (point != mLocalSyncPoints.end()) {
- if (!(*point)->frameIsAvailable() ||
- !(*point)->transactionIsApplied()) {
- // This sync point must have been added since we started
- // latching. Don't drop it yet.
- ++point;
- continue;
- }
-
- if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
- point = mLocalSyncPoints.erase(point);
- } else {
- ++point;
- }
- }
- }
-
- // FIXME: postedRegion should be dirty & bounds
- Region dirtyRegion(Rect(s.active.w, s.active.h));
-
- // transform the dirty region to window-manager space
- outDirtyRegion = (getTransform().transform(dirtyRegion));
-
- return outDirtyRegion;
-}
-
uint32_t Layer::getEffectiveUsage(uint32_t usage) const
{
// TODO: should we do something special if mSecure is set?
@@ -2432,7 +1707,9 @@
orientation = 0;
}
}
- mSurfaceFlingerConsumer->setTransformHint(orientation);
+ if (mSurfaceFlingerConsumer) {
+ mSurfaceFlingerConsumer->setTransformHint(orientation);
+ }
}
// ----------------------------------------------------------------------------
@@ -2584,6 +1861,10 @@
std::vector<OccupancyTracker::Segment> Layer::getOccupancyHistory(
bool forceFlush) {
std::vector<OccupancyTracker::Segment> history;
+
+ if (!mSurfaceFlingerConsumer)
+ return {};
+
status_t result = mSurfaceFlingerConsumer->getOccupancyHistory(forceFlush,
&history);
if (result != NO_ERROR) {
@@ -2595,7 +1876,10 @@
}
bool Layer::getTransformToDisplayInverse() const {
- return mSurfaceFlingerConsumer->getTransformToDisplayInverse();
+ if (mSurfaceFlingerConsumer) {
+ return mSurfaceFlingerConsumer->getTransformToDisplayInverse();
+ }
+ return false;
}
size_t Layer::getChildrenCount() const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index d75e175..ee3bb7e 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -69,14 +69,8 @@
// ---------------------------------------------------------------------------
-/*
- * 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 SurfaceFlingerConsumer::ContentsChangedListener {
+class Layer : public virtual RefBase
+{
static int32_t sSequence;
public:
@@ -162,18 +156,12 @@
half4 color;
};
- // -----------------------------------------------------------------------
-
Layer(SurfaceFlinger* flinger, const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags);
-
virtual ~Layer();
void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; }
- // the this layer's size and format
- status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
-
// ------------------------------------------------------------------------
// Geometry setting functions.
//
@@ -264,8 +252,7 @@
// -----------------------------------------------------------------------
// Virtuals
-
- virtual const char* getTypeId() const { return "Layer"; }
+ virtual const char* getTypeId() const = 0;
/*
* isOpaque - true if this surface is opaque
@@ -274,24 +261,18 @@
* pixel format includes an alpha channel) and the "opaque" flag set
* on the layer. It does not examine the current plane alpha value.
*/
- virtual bool isOpaque(const Layer::State& s) const;
+ virtual bool isOpaque(const Layer::State& s) const = 0;
/*
* isSecure - true if this surface is secure, that is if it prevents
* screenshots or VNC servers.
*/
- virtual bool isSecure() const;
-
- /*
- * isProtected - true if the layer may contain protected content in the
- * GRALLOC_USAGE_PROTECTED sense.
- */
- virtual bool isProtected() const;
+ bool isSecure() const;
/*
* isVisible - true if this layer is visible, false otherwise
*/
- virtual bool isVisible() const;
+ virtual bool isVisible() const = 0;
/*
* isHiddenByPolicy - true if this layer has been forced invisible.
@@ -299,12 +280,12 @@
* For example if this layer has no active buffer, it may not be hidden by
* policy, but it still can not be visible.
*/
- virtual bool isHiddenByPolicy() const;
+ bool isHiddenByPolicy() const;
/*
* isFixedSize - true if content has a fixed size
*/
- virtual bool isFixedSize() const;
+ virtual bool isFixedSize() const = 0;
void writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
@@ -313,11 +294,9 @@
* onDraw - draws the surface.
*/
virtual void onDraw(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform) const;
+ bool useIdentityTransform) const = 0;
public:
- // -----------------------------------------------------------------------
-
#ifdef USE_HWC2
void setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z);
void forceClientComposition(int32_t hwcId);
@@ -325,22 +304,17 @@
// callIntoHwc exists so we can update our local state and call
// acceptDisplayChanges without unnecessarily updating the device's state
- void setCompositionType(int32_t hwcId, HWC2::Composition type,
- bool callIntoHwc = true);
+ void setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc = true);
HWC2::Composition getCompositionType(int32_t hwcId) const;
-
void setClearClientTarget(int32_t hwcId, bool clear);
bool getClearClientTarget(int32_t hwcId) const;
-
void updateCursorPosition(const sp<const DisplayDevice>& hw);
#else
void setGeometry(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer);
- void setPerFrameData(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer);
+ HWComposer::HWCLayerInterface& layer);
+ void setPerFrameData(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer);
void setAcquireFence(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface& layer);
-
+ HWComposer::HWCLayerInterface& layer);
Rect getPosition(const sp<const DisplayDevice>& hw);
#endif
@@ -360,7 +334,7 @@
* called before composition.
* returns true if the layer has pending updates.
*/
- bool onPreComposition(nsecs_t refreshStartTime);
+ virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
/*
* called after composition.
@@ -372,7 +346,7 @@
#ifdef USE_HWC2
// If a buffer was replaced this frame, release the former buffer
- void releasePendingBuffer(nsecs_t dequeueReadyTime);
+ virtual void releasePendingBuffer(nsecs_t dequeueReadyTime) = 0;
#endif
/*
@@ -415,11 +389,10 @@
* 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.
*/
- Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime);
- bool isBufferLatched() const { return mRefreshPending; }
+ virtual Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0;
+ virtual bool isBufferLatched() const = 0;
- bool isPotentialCursor() const { return mPotentialCursor;}
-
+ bool isPotentialCursor() const { return mPotentialCursor; }
/*
* called with the state lock from a binder thread when the layer is
* removed from the current list to the pending removal list
@@ -526,14 +499,12 @@
ssize_t removeChild(const sp<Layer>& layer);
sp<Layer> getParent() const { return mCurrentParent.promote(); }
bool hasParent() const { return getParent() != nullptr; }
-
Rect computeScreenBounds(bool reduceTransparentRegion = true) const;
bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
// Copy the current list of children to the drawing state. Called by
// SurfaceFlinger to complete a transaction.
void commitChildList();
-
int32_t getZ() const;
protected:
// constant
@@ -562,39 +533,21 @@
-private:
friend class SurfaceInterceptor;
- // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
- virtual void onFrameAvailable(const BufferItem& item) override;
- virtual void onFrameReplaced(const BufferItem& item) override;
- virtual void onSidebandStreamChanged() override;
-
void commitTransaction(const State& stateToCommit);
- // needsLinearFiltering - true if this surface's state requires filtering
- bool needsFiltering(const RenderArea& renderArea) const;
-
uint32_t getEffectiveUsage(uint32_t usage) const;
FloatRect computeCrop(const sp<const DisplayDevice>& hw) const;
- // Compute the initial crop as specified by parent layers and the SurfaceControl
- // for this layer. Does not include buffer crop from the IGraphicBufferProducer
- // client, as that should not affect child clipping. Returns in screen space.
+ // Compute the initial crop as specified by parent layers and the
+ // SurfaceControl for this layer. Does not include buffer crop from the
+ // IGraphicBufferProducer client, as that should not affect child clipping.
+ // Returns in screen space.
Rect computeInitialCrop(const sp<const DisplayDevice>& hw) const;
- bool isCropped() const;
- static bool getOpacityForFormat(uint32_t format);
// drawing
void clearWithOpenGL(const RenderArea& renderArea,
float r, float g, float b, float alpha) const;
- void drawWithOpenGL(const RenderArea& renderArea,
- bool useIdentityTransform) const;
-
- // Temporary - Used only for LEGACY camera mode.
- uint32_t getProducerStickyTransform() const;
-
- // Loads the corresponding system property once per process
- static bool latchUnsignaledBuffers();
void setParent(const sp<Layer>& layer);
@@ -602,8 +555,7 @@
void addZOrderRelative(const wp<Layer>& relative);
void removeZOrderRelative(const wp<Layer>& relative);
- // -----------------------------------------------------------------------
-
+protected:
class SyncPoint
{
public:
@@ -646,9 +598,6 @@
// is applied
std::list<std::shared_ptr<SyncPoint>> mRemoteSyncPoints;
- uint64_t getHeadFrameNumber() const;
- bool headFenceHasSignaled() const;
-
// Returns false if the relevant frame has already been latched
bool addSyncPoint(const std::shared_ptr<SyncPoint>& point);
@@ -661,7 +610,7 @@
// Returns mCurrentScaling mode (originating from the
// Client) or mOverrideScalingMode mode (originating from
// the Surface Controller) if set.
- uint32_t getEffectiveScalingMode() const;
+ virtual uint32_t getEffectiveScalingMode() const = 0;
public:
/*
* The layer handle is just a BBinder object passed to the client
@@ -680,28 +629,19 @@
};
sp<IBinder> getHandle();
- sp<IGraphicBufferProducer> getProducer() const;
const String8& getName() const;
- void notifyAvailableFrames();
- PixelFormat getPixelFormat() const { return mFormat; }
+ virtual void notifyAvailableFrames() = 0;
+ virtual PixelFormat getPixelFormat() const = 0;
bool getPremultipledAlpha() const;
-private:
+protected:
// -----------------------------------------------------------------------
- // Check all of the local sync points to ensure that all transactions
- // which need to have been applied prior to the frame which is about to
- // be latched have signaled
- bool allTransactionsSignaled();
-
// constants
sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer;
- sp<IGraphicBufferProducer> mProducer;
- uint32_t mTextureName; // from GLES
bool mPremultipliedAlpha;
String8 mName;
- String8 mTransactionName; // A cached version of "TX - " + mName for systraces
- PixelFormat mFormat;
+ String8 mTransactionName; // A cached version of "TX - " + mName for systraces
bool mPrimaryDisplayOnly = false;
@@ -716,7 +656,7 @@
// thread-safe
volatile int32_t mQueuedFrames;
- volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
+ volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
// Timestamp history for UIAutomation. Thread safe.
FrameTracker mFrameTracker;
@@ -734,14 +674,10 @@
sp<NativeHandle> mSidebandStream;
Rect mCurrentCrop;
uint32_t mCurrentTransform;
- uint32_t mCurrentScalingMode;
// We encode unset as -1.
int32_t mOverrideScalingMode;
bool mCurrentOpacity;
- bool mBufferLatched = false; // TODO: Use mActiveBuffer?
std::atomic<uint64_t> mCurrentFrameNumber;
- uint64_t mPreviousFrameNumber; // Only accessed on the main thread.
- bool mRefreshPending;
bool mFrameLatencyNeeded;
// Whether filtering is forced on or not
bool mFiltering;
@@ -749,8 +685,7 @@
bool mNeedsFiltering;
// The mesh used to draw the layer in GLES composition mode
mutable Mesh mMesh;
- // The texture used to draw the layer in GLES composition mode
- mutable Texture mTexture;
+
#ifdef USE_HWC2
// HWC items, accessed from the main thread
@@ -786,8 +721,7 @@
// protected by mLock
mutable Mutex mLock;
- // Set to true once we've returned this surface's handle
- mutable bool mHasSurface;
+
const wp<Client> mClientRef;
// This layer can be a cursor on some displays.
@@ -798,8 +732,6 @@
Condition mQueueItemCondition;
Vector<BufferItem> mQueueItems;
std::atomic<uint64_t> mLastFrameNumberReceived;
- bool mUpdateTexImageFailed; // This is only accessed on the main thread.
-
bool mAutoRefresh;
bool mFreezeGeometryUpdates;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 77b9a29..e40bbd5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -72,6 +72,7 @@
#include "EventControlThread.h"
#include "EventThread.h"
#include "Layer.h"
+#include "BufferLayer.h"
#include "LayerVector.h"
#include "ColorLayer.h"
#include "MonitoredProducer.h"
@@ -3208,14 +3209,15 @@
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceNormal:
- result = createNormalLayer(client,
+ result = createBufferLayer(client,
uniqueName, w, h, flags, format,
handle, gbp, &layer);
+
break;
case ISurfaceComposerClient::eFXSurfaceColor:
result = createColorLayer(client,
uniqueName, w, h, flags,
- handle, gbp, &layer);
+ handle, &layer);
break;
default:
result = BAD_VALUE;
@@ -3269,7 +3271,7 @@
return uniqueName;
}
-status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
+status_t SurfaceFlinger::createBufferLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
@@ -3284,24 +3286,24 @@
break;
}
- *outLayer = new Layer(this, client, name, w, h, flags);
- status_t err = (*outLayer)->setBuffers(w, h, format, flags);
+ sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags);
+ status_t err = layer->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
- *handle = (*outLayer)->getHandle();
- *gbp = (*outLayer)->getProducer();
+ *handle = layer->getHandle();
+ *gbp = layer->getProducer();
+ *outLayer = layer;
}
- ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
+ ALOGE_IF(err, "createBufferLayer() failed (%s)", strerror(-err));
return err;
}
status_t SurfaceFlinger::createColorLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags,
- sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
+ sp<IBinder>* handle, sp<Layer>* outLayer)
{
*outLayer = new ColorLayer(this, client, name, w, h, flags);
*handle = (*outLayer)->getHandle();
- *gbp = (*outLayer)->getProducer();
return NO_ERROR;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index d0f4699..d10b41b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -244,6 +244,7 @@
friend class DisplayEventConnection;
friend class EventThread;
friend class Layer;
+ friend class BufferLayer;
friend class MonitoredProducer;
// This value is specified in number of frames. Log frame stats at most
@@ -419,14 +420,14 @@
uint32_t windowType, uint32_t ownerUid, sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent);
- status_t createNormalLayer(const sp<Client>& client, const String8& name,
+ status_t createBufferLayer(const sp<Client>& client, const String8& name,
uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp,
sp<Layer>* outLayer);
status_t createColorLayer(const sp<Client>& client, const String8& name,
uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
- sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
+ sp<Layer>* outLayer);
String8 getUniqueLayerName(const String8& name);
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 952023e..714c23d 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -70,6 +70,7 @@
#include "EventControlThread.h"
#include "EventThread.h"
#include "Layer.h"
+#include "BufferLayer.h"
#include "LayerVector.h"
#include "ColorLayer.h"
#include "MonitoredProducer.h"
@@ -2733,14 +2734,14 @@
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceNormal:
- result = createNormalLayer(client,
+ result = createBufferLayer(client,
uniqueName, w, h, flags, format,
handle, gbp, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceColor:
result = createColorLayer(client,
uniqueName, w, h, flags,
- handle, gbp, &layer);
+ handle, &layer);
break;
default:
result = BAD_VALUE;
@@ -2787,7 +2788,7 @@
return uniqueName;
}
-status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
+status_t SurfaceFlinger::createBufferLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
@@ -2802,24 +2803,24 @@
break;
}
- *outLayer = new Layer(this, client, name, w, h, flags);
- status_t err = (*outLayer)->setBuffers(w, h, format, flags);
+ sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags);
+ status_t err = layer->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
- *handle = (*outLayer)->getHandle();
- *gbp = (*outLayer)->getProducer();
+ *handle = layer->getHandle();
+ *gbp = layer->getProducer();
+ *outLayer = layer;
}
- ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
+ ALOGE_IF(err, "createBufferLayer() failed (%s)", strerror(-err));
return err;
}
status_t SurfaceFlinger::createColorLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags,
- sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
+ sp<IBinder>* handle, sp<Layer>* outLayer)
{
*outLayer = new ColorLayer(this, client, name, w, h, flags);
*handle = (*outLayer)->getHandle();
- *gbp = (*outLayer)->getProducer();
return NO_ERROR;
}