From 9d763b7014c9f16172d5a43fe8574add0daa23c0 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Mon, 20 Apr 2020 18:42:31 -0700 Subject: Do not blur when doing region sampling The luma approximation will already be pretty good without the blurs. Test: RegionSamplingTest Test: libsurfaceflinger_test Fixes: 154556259 Change-Id: I4010ac54aee2e23bd8cf155f591584eeec425702 --- services/surfaceflinger/RegionSamplingThread.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 68cd84f661..6e59034133 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -430,7 +430,8 @@ void RegionSamplingThread::captureSample() { } bool ignored; - mFlinger.captureScreenCommon(renderArea, traverseLayers, buffer, false, ignored); + mFlinger.captureScreenCommon(renderArea, traverseLayers, buffer, false /* identityTransform */, + true /* regionSampling */, ignored); std::vector activeDescriptors; for (const auto& descriptor : descriptors) { -- cgit v1.2.3-59-g8ed1b From 1c43429785fb9adda0726b5480a59f476d066e83 Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Fri, 12 Jun 2020 01:47:29 +0200 Subject: [SF] Don't keep sp when doing screenshot If a hotplug event is processed while a screenshot is taken the system may crash because binder thread can end up holding the last sp<> to a DisplayDevice. In this change we store a weak pointer and promote to a strong pointer when we are on the main thread. Bug: 158599281 Test: atest libsurfaceflinger_unittest Change-Id: Ica09398a48e68ec7b6bda3b88a6dadfa27b3455d --- services/surfaceflinger/DisplayDevice.h | 39 +++--- .../surfaceflinger/DisplayHardware/HWComposer.h | 2 + services/surfaceflinger/RegionSamplingThread.cpp | 54 ++++++--- services/surfaceflinger/RenderArea.h | 15 +-- services/surfaceflinger/SurfaceFlinger.cpp | 134 ++++++++++++--------- services/surfaceflinger/SurfaceFlinger.h | 14 +-- .../tests/unittests/CompositionTest.cpp | 11 +- .../tests/unittests/TestableSurfaceFlinger.h | 6 +- 8 files changed, 157 insertions(+), 118 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 4dabd2b566..81b3ccf70c 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -59,12 +59,14 @@ class Display; class DisplaySurface; } // namespace compositionengine -class DisplayDevice : public LightRefBase { +class DisplayDevice : public RefBase { public: constexpr static float sDefaultMinLumiance = 0.0; constexpr static float sDefaultMaxLumiance = 500.0; explicit DisplayDevice(DisplayDeviceCreationArgs& args); + + // Must be destroyed on the main thread because it may call into HWComposer. virtual ~DisplayDevice(); std::shared_ptr getCompositionDisplay() const { @@ -246,21 +248,18 @@ struct DisplayDeviceCreationArgs { class DisplayRenderArea : public RenderArea { public: - DisplayRenderArea(const sp& display, - RotationFlags rotation = ui::Transform::ROT_0) - : DisplayRenderArea(display, display->getBounds(), - static_cast(display->getWidth()), - static_cast(display->getHeight()), - display->getCompositionDataSpace(), rotation) {} - - DisplayRenderArea(sp display, const Rect& sourceCrop, uint32_t reqWidth, - uint32_t reqHeight, ui::Dataspace reqDataSpace, RotationFlags rotation, - bool allowSecureLayers = true) - : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, reqDataSpace, - display->getViewport(), applyDeviceOrientation(rotation, display)), - mDisplay(std::move(display)), - mSourceCrop(sourceCrop), - mAllowSecureLayers(allowSecureLayers) {} + static std::unique_ptr create(wp displayWeak, + const Rect& sourceCrop, ui::Size reqSize, + ui::Dataspace reqDataSpace, RotationFlags rotation, + bool allowSecureLayers = true) { + if (auto display = displayWeak.promote()) { + // Using new to access a private constructor. + return std::unique_ptr( + new DisplayRenderArea(std::move(display), sourceCrop, reqSize, reqDataSpace, + rotation, allowSecureLayers)); + } + return nullptr; + } const ui::Transform& getTransform() const override { return mTransform; } Rect getBounds() const override { return mDisplay->getBounds(); } @@ -307,6 +306,14 @@ public: } private: + DisplayRenderArea(sp display, const Rect& sourceCrop, ui::Size reqSize, + ui::Dataspace reqDataSpace, RotationFlags rotation, bool allowSecureLayers) + : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, display->getViewport(), + applyDeviceOrientation(rotation, display)), + mDisplay(std::move(display)), + mSourceCrop(sourceCrop), + mAllowSecureLayers(allowSecureLayers) {} + static RotationFlags applyDeviceOrientation(RotationFlags orientationFlag, const sp& device) { uint32_t inverseRotate90 = 0; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index c355ebd4a6..b8000386ac 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -64,6 +64,8 @@ struct KnownHWCGenericLayerMetadata { const uint32_t id; }; +// See the comment for SurfaceFlinger::getHwComposer for the thread safety rules for accessing +// this class. class HWComposer { public: struct DeviceRequestedChanges { diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 27353d8c0b..398fd40442 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -36,6 +36,7 @@ #include "DisplayDevice.h" #include "Layer.h" +#include "Promise.h" #include "Scheduler/DispSync.h" #include "SurfaceFlinger.h" @@ -336,8 +337,20 @@ void RegionSamplingThread::captureSample() { return; } - const auto device = mFlinger.getDefaultDisplayDevice(); - const auto orientation = ui::Transform::toRotationFlags(device->getOrientation()); + wp displayWeak; + + ui::LayerStack layerStack; + ui::Transform::RotationFlags orientation; + ui::Size displaySize; + + { + // TODO(b/159112860): Don't keep sp outside of SF main thread + const sp display = mFlinger.getDefaultDisplayDevice(); + displayWeak = display; + layerStack = display->getLayerStack(); + orientation = ui::Transform::toRotationFlags(display->getOrientation()); + displaySize = display->getSize(); + } std::vector descriptors; Region sampleRegion; @@ -346,20 +359,18 @@ void RegionSamplingThread::captureSample() { descriptors.emplace_back(descriptor); } - const Rect sampledArea = sampleRegion.bounds(); - auto dx = 0; auto dy = 0; switch (orientation) { case ui::Transform::ROT_90: - dx = device->getWidth(); + dx = displaySize.getWidth(); break; case ui::Transform::ROT_180: - dx = device->getWidth(); - dy = device->getHeight(); + dx = displaySize.getWidth(); + dy = displaySize.getHeight(); break; case ui::Transform::ROT_270: - dy = device->getHeight(); + dy = displaySize.getHeight(); break; default: break; @@ -368,8 +379,13 @@ void RegionSamplingThread::captureSample() { ui::Transform t(orientation); auto screencapRegion = t.transform(sampleRegion); screencapRegion = screencapRegion.translate(dx, dy); - DisplayRenderArea renderArea(device, screencapRegion.bounds(), sampledArea.getWidth(), - sampledArea.getHeight(), ui::Dataspace::V0_SRGB, orientation); + + const Rect sampledBounds = sampleRegion.bounds(); + + SurfaceFlinger::RenderAreaFuture renderAreaFuture = promise::defer([=] { + return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(), + ui::Dataspace::V0_SRGB, orientation); + }); std::unordered_set, SpHash> listeners; @@ -393,9 +409,9 @@ void RegionSamplingThread::captureSample() { constexpr bool roundOutwards = true; Rect transformed = transform.transform(bounds, roundOutwards); - // If this layer doesn't intersect with the larger sampledArea, skip capturing it + // If this layer doesn't intersect with the larger sampledBounds, skip capturing it Rect ignore; - if (!transformed.intersect(sampledArea, &ignore)) return; + if (!transformed.intersect(sampledBounds, &ignore)) return; // If the layer doesn't intersect a sampling area, skip capturing it bool intersectsAnyArea = false; @@ -411,22 +427,22 @@ void RegionSamplingThread::captureSample() { bounds.top, bounds.right, bounds.bottom); visitor(layer); }; - mFlinger.traverseLayersInDisplay(device, filterVisitor); + mFlinger.traverseLayersInLayerStack(layerStack, filterVisitor); }; sp buffer = nullptr; - if (mCachedBuffer && mCachedBuffer->getWidth() == sampledArea.getWidth() && - mCachedBuffer->getHeight() == sampledArea.getHeight()) { + if (mCachedBuffer && mCachedBuffer->getWidth() == sampledBounds.getWidth() && + mCachedBuffer->getHeight() == sampledBounds.getHeight()) { buffer = mCachedBuffer; } else { const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER; - buffer = new GraphicBuffer(sampledArea.getWidth(), sampledArea.getHeight(), + buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); } bool ignored; - mFlinger.captureScreenCommon(renderArea, traverseLayers, buffer, false /* identityTransform */, - true /* regionSampling */, ignored); + mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, + false /* identityTransform */, true /* regionSampling */, ignored); std::vector activeDescriptors; for (const auto& descriptor : descriptors) { @@ -437,7 +453,7 @@ void RegionSamplingThread::captureSample() { ALOGV("Sampling %zu descriptors", activeDescriptors.size()); std::vector lumas = - sampleBuffer(buffer, sampledArea.leftTop(), activeDescriptors, orientation); + sampleBuffer(buffer, sampledBounds.leftTop(), activeDescriptors, orientation); if (lumas.size() != activeDescriptors.size()) { ALOGW("collected %zu median luma values for %zu descriptors", lumas.size(), activeDescriptors.size()); diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h index 6b0455ae87..a6246d9a6a 100644 --- a/services/surfaceflinger/RenderArea.h +++ b/services/surfaceflinger/RenderArea.h @@ -23,11 +23,9 @@ public: static float getCaptureFillValue(CaptureFill captureFill); - RenderArea(uint32_t reqWidth, uint32_t reqHeight, CaptureFill captureFill, - ui::Dataspace reqDataSpace, const Rect& displayViewport, - RotationFlags rotation = ui::Transform::ROT_0) - : mReqWidth(reqWidth), - mReqHeight(reqHeight), + RenderArea(ui::Size reqSize, CaptureFill captureFill, ui::Dataspace reqDataSpace, + const Rect& displayViewport, RotationFlags rotation = ui::Transform::ROT_0) + : mReqSize(reqSize), mReqDataSpace(reqDataSpace), mCaptureFill(captureFill), mRotationFlags(rotation), @@ -70,8 +68,8 @@ public: RotationFlags getRotationFlags() const { return mRotationFlags; } // Returns the size of the physical render area. - int getReqWidth() const { return static_cast(mReqWidth); } - int getReqHeight() const { return static_cast(mReqHeight); } + int getReqWidth() const { return mReqSize.width; } + int getReqHeight() const { return mReqSize.height; } // Returns the composition data space of the render area. ui::Dataspace getReqDataSpace() const { return mReqDataSpace; } @@ -86,8 +84,7 @@ public: const Rect& getDisplayViewport() const { return mDisplayViewport; } private: - const uint32_t mReqWidth; - const uint32_t mReqHeight; + const ui::Size mReqSize; const ui::Dataspace mReqDataSpace; const CaptureFill mCaptureFill; const RotationFlags mRotationFlags; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 36d272ae99..9fd0f656a4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5383,27 +5383,33 @@ status_t SurfaceFlinger::captureScreen(const sp& displayToken, renderAreaRotation = ui::Transform::ROT_0; } - sp display; + wp displayWeak; + ui::LayerStack layerStack; + ui::Size reqSize(reqWidth, reqHeight); { Mutex::Autolock lock(mStateLock); - - display = getDisplayDeviceLocked(displayToken); + sp display = getDisplayDeviceLocked(displayToken); if (!display) return NAME_NOT_FOUND; + displayWeak = display; + layerStack = display->getLayerStack(); // set the requested width/height to the logical display viewport size // by default if (reqWidth == 0 || reqHeight == 0) { - reqWidth = uint32_t(display->getViewport().width()); - reqHeight = uint32_t(display->getViewport().height()); + reqSize = display->getViewport().getSize(); } } - DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace, - renderAreaRotation, captureSecureLayers); - auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display, - std::placeholders::_1); - return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, - useIdentityTransform, outCapturedSecureLayers); + RenderAreaFuture renderAreaFuture = promise::defer([=] { + return DisplayRenderArea::create(displayWeak, sourceCrop, reqSize, reqDataspace, + renderAreaRotation, captureSecureLayers); + }); + + auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) { + traverseLayersInLayerStack(layerStack, visitor); + }; + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, outBuffer, + reqPixelFormat, useIdentityTransform, outCapturedSecureLayers); } static Dataspace pickDataspaceFromColorMode(const ColorMode colorMode) { @@ -5459,19 +5465,20 @@ sp SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) { status_t SurfaceFlinger::captureScreen(uint64_t displayOrLayerStack, Dataspace* outDataspace, sp* outBuffer) { - sp display; - uint32_t width; - uint32_t height; + ui::LayerStack layerStack; + wp displayWeak; + ui::Size size; ui::Transform::RotationFlags captureOrientation; { Mutex::Autolock lock(mStateLock); - display = getDisplayByIdOrLayerStack(displayOrLayerStack); + sp display = getDisplayByIdOrLayerStack(displayOrLayerStack); if (!display) { return NAME_NOT_FOUND; } + layerStack = display->getLayerStack(); + displayWeak = display; - width = uint32_t(display->getViewport().width()); - height = uint32_t(display->getViewport().height()); + size = display->getViewport().getSize(); const auto orientation = display->getOrientation(); captureOrientation = ui::Transform::toRotationFlags(orientation); @@ -5497,14 +5504,19 @@ status_t SurfaceFlinger::captureScreen(uint64_t displayOrLayerStack, Dataspace* pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode); } - DisplayRenderArea renderArea(display, Rect(), width, height, *outDataspace, captureOrientation, - false /* captureSecureLayers */); + RenderAreaFuture renderAreaFuture = promise::defer([=] { + return DisplayRenderArea::create(displayWeak, Rect(), size, *outDataspace, + captureOrientation, false /* captureSecureLayers */); + }); + + auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) { + traverseLayersInLayerStack(layerStack, visitor); + }; - auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display, - std::placeholders::_1); bool ignored = false; - return captureScreenCommon(renderArea, traverseLayers, outBuffer, ui::PixelFormat::RGBA_8888, - false /* useIdentityTransform */, + + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, outBuffer, + ui::PixelFormat::RGBA_8888, false /* useIdentityTransform */, ignored /* outCapturedSecureLayers */); } @@ -5518,9 +5530,9 @@ status_t SurfaceFlinger::captureLayers( class LayerRenderArea : public RenderArea { public: LayerRenderArea(SurfaceFlinger* flinger, const sp& layer, const Rect crop, - int32_t reqWidth, int32_t reqHeight, Dataspace reqDataSpace, - bool childrenOnly, const Rect& displayViewport) - : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR, reqDataSpace, displayViewport), + ui::Size reqSize, Dataspace reqDataSpace, bool childrenOnly, + const Rect& displayViewport) + : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, displayViewport), mLayer(layer), mCrop(crop), mNeedsFiltering(false), @@ -5595,8 +5607,7 @@ status_t SurfaceFlinger::captureLayers( const bool mChildrenOnly; }; - int reqWidth = 0; - int reqHeight = 0; + ui::Size reqSize; sp parent; Rect crop(sourceCrop); std::unordered_set, ISurfaceComposer::SpHash> excludeLayers; @@ -5633,8 +5644,7 @@ status_t SurfaceFlinger::captureLayers( // crop was not specified, or an invalid frame scale was provided. return BAD_VALUE; } - reqWidth = crop.width() * frameScale; - reqHeight = crop.height() * frameScale; + reqSize = ui::Size(crop.width() * frameScale, crop.height() * frameScale); for (const auto& handle : excludeHandles) { sp excludeLayer = fromHandleLocked(handle).promote(); @@ -5655,15 +5665,18 @@ status_t SurfaceFlinger::captureLayers( } // mStateLock // really small crop or frameScale - if (reqWidth <= 0) { - reqWidth = 1; + if (reqSize.width <= 0) { + reqSize.width = 1; } - if (reqHeight <= 0) { - reqHeight = 1; + if (reqSize.height <= 0) { + reqSize.height = 1; } - LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, reqDataspace, childrenOnly, - displayViewport); + RenderAreaFuture renderAreaFuture = promise::defer([=]() -> std::unique_ptr { + return std::make_unique(this, parent, crop, reqSize, reqDataspace, + childrenOnly, displayViewport); + }); + auto traverseLayers = [parent, childrenOnly, &excludeLayers](const LayerVector::Visitor& visitor) { parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { @@ -5686,14 +5699,14 @@ status_t SurfaceFlinger::captureLayers( }; bool outCapturedSecureLayers = false; - return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, false, - outCapturedSecureLayers); + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, outBuffer, + reqPixelFormat, false, outCapturedSecureLayers); } -status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, +status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, - sp* outBuffer, - const ui::PixelFormat reqPixelFormat, + ui::Size bufferSize, sp* outBuffer, + ui::PixelFormat reqPixelFormat, bool useIdentityTransform, bool& outCapturedSecureLayers) { ATRACE_CALL(); @@ -5701,16 +5714,16 @@ status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, // TODO(b/116112787) Make buffer usage a parameter. const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - *outBuffer = - getFactory().createGraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(), - static_cast(reqPixelFormat), 1, - usage, "screenshot"); + *outBuffer = getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(), + static_cast(reqPixelFormat), + 1, usage, "screenshot"); - return captureScreenCommon(renderArea, traverseLayers, *outBuffer, useIdentityTransform, - false /* regionSampling */, outCapturedSecureLayers); + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, *outBuffer, + useIdentityTransform, false /* regionSampling */, + outCapturedSecureLayers); } -status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, +status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, const sp& buffer, bool useIdentityTransform, bool regionSampling, @@ -5723,23 +5736,28 @@ status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, do { std::tie(result, syncFd) = - schedule([&] { + schedule([&]() -> std::pair { if (mRefreshPending) { - ATRACE_NAME("Skipping screenshot for now"); - return std::make_pair(EAGAIN, -1); + ALOGW("Skipping screenshot for now"); + return {EAGAIN, -1}; + } + std::unique_ptr renderArea = renderAreaFuture.get(); + if (!renderArea) { + ALOGW("Skipping screen capture because of invalid render area."); + return {NO_MEMORY, -1}; } status_t result = NO_ERROR; int fd = -1; Mutex::Autolock lock(mStateLock); - renderArea.render([&] { - result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(), + renderArea->render([&] { + result = captureScreenImplLocked(*renderArea, traverseLayers, buffer.get(), useIdentityTransform, forSystem, &fd, regionSampling, outCapturedSecureLayers); }); - return std::make_pair(result, fd); + return {result, fd}; }).get(); } while (result == EAGAIN); @@ -5898,17 +5916,17 @@ void SurfaceFlinger::State::traverseInReverseZOrder(const LayerVector::Visitor& layersSortedByZ.traverseInReverseZOrder(stateSet, visitor); } -void SurfaceFlinger::traverseLayersInDisplay(const sp& display, - const LayerVector::Visitor& visitor) { +void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack, + const LayerVector::Visitor& visitor) { // We loop through the first level of layers without traversing, // as we need to determine which layers belong to the requested display. for (const auto& layer : mDrawingState.layersSortedByZ) { - if (!layer->belongsToDisplay(display->getLayerStack(), false)) { + if (!layer->belongsToDisplay(layerStack, false)) { continue; } // relative layers are traversed in Layer::traverseInZOrder layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - if (!layer->belongsToDisplay(display->getLayerStack(), false)) { + if (!layer->belongsToDisplay(layerStack, false)) { return; } if (!layer->isVisible()) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8d3211b3e2..35648ceb65 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -711,16 +711,17 @@ private: void startBootAnim(); using TraverseLayersFunction = std::function; + using RenderAreaFuture = std::future>; void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, const sp& buffer, bool useIdentityTransform, bool regionSampling, int* outSyncFd); - status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers, - sp* outBuffer, const ui::PixelFormat reqPixelFormat, + status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, + sp* outBuffer, ui::PixelFormat, bool useIdentityTransform, bool& outCapturedSecureLayers); - status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers, - const sp& buffer, bool useIdentityTransform, - bool regionSampling, bool& outCapturedSecureLayers); + status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, const sp&, + bool useIdentityTransform, bool regionSampling, + bool& outCapturedSecureLayers); sp getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); sp getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock); status_t captureScreenImplLocked(const RenderArea& renderArea, @@ -728,8 +729,7 @@ private: const sp& buffer, bool useIdentityTransform, bool forSystem, int* outSyncFd, bool regionSampling, bool& outCapturedSecureLayers); - void traverseLayersInDisplay(const sp& display, - const LayerVector::Visitor& visitor); + void traverseLayersInLayerStack(ui::LayerStack, const LayerVector::Visitor&); sp mStartPropertySetThread; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 95e2ef5820..456891e11f 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -233,23 +233,22 @@ void CompositionTest::captureScreenComposition() { constexpr bool forSystem = true; constexpr bool regionSampling = false; - DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH, - DEFAULT_DISPLAY_HEIGHT, ui::Dataspace::V0_SRGB, - ui::Transform::ROT_0); + auto renderArea = DisplayRenderArea::create(mDisplay, sourceCrop, sourceCrop.getSize(), + ui::Dataspace::V0_SRGB, ui::Transform::ROT_0); auto traverseLayers = [this](const LayerVector::Visitor& visitor) { - return mFlinger.traverseLayersInDisplay(mDisplay, visitor); + return mFlinger.traverseLayersInLayerStack(mDisplay->getLayerStack(), visitor); }; // TODO: Eliminate expensive/real allocation if possible. const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - mCaptureScreenBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(), + mCaptureScreenBuffer = new GraphicBuffer(renderArea->getReqWidth(), renderArea->getReqHeight(), HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot"); int fd = -1; status_t result = - mFlinger.captureScreenImplLocked(renderArea, traverseLayers, mCaptureScreenBuffer.get(), + mFlinger.captureScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer.get(), useIdentityTransform, forSystem, &fd, regionSampling); if (fd >= 0) { close(fd); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 4652da01ab..f630103cb6 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -341,9 +341,9 @@ public: regionSampling, ignored); } - auto traverseLayersInDisplay(const sp& display, - const LayerVector::Visitor& visitor) { - return mFlinger->SurfaceFlinger::traverseLayersInDisplay(display, visitor); + auto traverseLayersInLayerStack(ui::LayerStack layerStack, + const LayerVector::Visitor& visitor) { + return mFlinger->SurfaceFlinger::traverseLayersInLayerStack(layerStack, visitor); } auto getDisplayNativePrimaries(const sp& displayToken, -- cgit v1.2.3-59-g8ed1b From f6b5d187b9a0520284f35a00eaf16335222a036a Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Fri, 12 Jun 2020 02:08:51 +0200 Subject: [SF] Extract {Display|Layer}RenderArea to separate files This CL also fixes incorrect sampling bounds in RegionSamplingThread, caused by ag/11837111. Bug: 158599281 Test: atest libsurfaceflinger_unittest Test: take a screenshot from launcher Test: take a screenshot from YouTube while playing a video Change-Id: I7e7777071e91a833a7bad4bd77e9d0c989fea9b7 --- services/surfaceflinger/Android.bp | 2 + services/surfaceflinger/DisplayDevice.h | 120 ---------------- services/surfaceflinger/DisplayRenderArea.cpp | 154 +++++++++++++++++++++ services/surfaceflinger/DisplayRenderArea.h | 54 ++++++++ services/surfaceflinger/LayerRenderArea.cpp | 113 +++++++++++++++ services/surfaceflinger/LayerRenderArea.h | 60 ++++++++ services/surfaceflinger/RegionSamplingThread.cpp | 6 +- services/surfaceflinger/SurfaceFlinger.cpp | 84 +---------- services/surfaceflinger/SurfaceFlinger.h | 1 + .../tests/unittests/CompositionTest.cpp | 6 +- 10 files changed, 395 insertions(+), 205 deletions(-) create mode 100644 services/surfaceflinger/DisplayRenderArea.cpp create mode 100644 services/surfaceflinger/DisplayRenderArea.h create mode 100644 services/surfaceflinger/LayerRenderArea.cpp create mode 100644 services/surfaceflinger/LayerRenderArea.h (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index a790d0b745..804a3c388b 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -145,6 +145,7 @@ filegroup { "DisplayHardware/HWComposer.cpp", "DisplayHardware/PowerAdvisor.cpp", "DisplayHardware/VirtualDisplaySurface.cpp", + "DisplayRenderArea.cpp", "Effects/Daltonizer.cpp", "EventLog/EventLog.cpp", "FrameTracer/FrameTracer.cpp", @@ -152,6 +153,7 @@ filegroup { "Layer.cpp", "LayerProtoHelper.cpp", "LayerRejecter.cpp", + "LayerRenderArea.cpp", "LayerVector.cpp", "MonitoredProducer.cpp", "NativeWindowSurface.cpp", diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 81b3ccf70c..576488c558 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -40,7 +40,6 @@ #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/Hal.h" #include "DisplayHardware/PowerAdvisor.h" -#include "RenderArea.h" #include "Scheduler/HwcStrongTypes.h" namespace android { @@ -246,123 +245,4 @@ struct DisplayDeviceCreationArgs { bool isPrimary{false}; }; -class DisplayRenderArea : public RenderArea { -public: - static std::unique_ptr create(wp displayWeak, - const Rect& sourceCrop, ui::Size reqSize, - ui::Dataspace reqDataSpace, RotationFlags rotation, - bool allowSecureLayers = true) { - if (auto display = displayWeak.promote()) { - // Using new to access a private constructor. - return std::unique_ptr( - new DisplayRenderArea(std::move(display), sourceCrop, reqSize, reqDataSpace, - rotation, allowSecureLayers)); - } - return nullptr; - } - - const ui::Transform& getTransform() const override { return mTransform; } - Rect getBounds() const override { return mDisplay->getBounds(); } - int getHeight() const override { return mDisplay->getHeight(); } - int getWidth() const override { return mDisplay->getWidth(); } - bool isSecure() const override { return mAllowSecureLayers && mDisplay->isSecure(); } - sp getDisplayDevice() const override { return mDisplay; } - - bool needsFiltering() const override { - // check if the projection from the logical render area - // to the physical render area requires filtering - const Rect& sourceCrop = getSourceCrop(); - int width = sourceCrop.width(); - int height = sourceCrop.height(); - if (getRotationFlags() & ui::Transform::ROT_90) { - std::swap(width, height); - } - return width != getReqWidth() || height != getReqHeight(); - } - - Rect getSourceCrop() const override { - // use the projected display viewport by default. - if (mSourceCrop.isEmpty()) { - return mDisplay->getSourceClip(); - } - - // If there is a source crop provided then it is assumed that the device - // was in portrait orientation. This may not logically be true, so - // correct for the orientation error by undoing the rotation - - ui::Rotation logicalOrientation = mDisplay->getOrientation(); - if (logicalOrientation == ui::Rotation::Rotation90) { - logicalOrientation = ui::Rotation::Rotation270; - } else if (logicalOrientation == ui::Rotation::Rotation270) { - logicalOrientation = ui::Rotation::Rotation90; - } - - const auto flags = ui::Transform::toRotationFlags(logicalOrientation); - int width = mDisplay->getSourceClip().getWidth(); - int height = mDisplay->getSourceClip().getHeight(); - ui::Transform rotation; - rotation.set(flags, width, height); - return rotation.transform(mSourceCrop); - } - -private: - DisplayRenderArea(sp display, const Rect& sourceCrop, ui::Size reqSize, - ui::Dataspace reqDataSpace, RotationFlags rotation, bool allowSecureLayers) - : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, display->getViewport(), - applyDeviceOrientation(rotation, display)), - mDisplay(std::move(display)), - mSourceCrop(sourceCrop), - mAllowSecureLayers(allowSecureLayers) {} - - static RotationFlags applyDeviceOrientation(RotationFlags orientationFlag, - const sp& device) { - uint32_t inverseRotate90 = 0; - uint32_t inverseReflect = 0; - - // Reverse the logical orientation. - ui::Rotation logicalOrientation = device->getOrientation(); - if (logicalOrientation == ui::Rotation::Rotation90) { - logicalOrientation = ui::Rotation::Rotation270; - } else if (logicalOrientation == ui::Rotation::Rotation270) { - logicalOrientation = ui::Rotation::Rotation90; - } - - const ui::Rotation orientation = device->getPhysicalOrientation() + logicalOrientation; - - switch (orientation) { - case ui::ROTATION_0: - return orientationFlag; - - case ui::ROTATION_90: - inverseRotate90 = ui::Transform::ROT_90; - inverseReflect = ui::Transform::ROT_180; - break; - - case ui::ROTATION_180: - inverseReflect = ui::Transform::ROT_180; - break; - - case ui::ROTATION_270: - inverseRotate90 = ui::Transform::ROT_90; - break; - } - - const uint32_t rotate90 = orientationFlag & ui::Transform::ROT_90; - uint32_t reflect = orientationFlag & ui::Transform::ROT_180; - - // Apply reflection for double rotation. - if (rotate90 & inverseRotate90) { - reflect = ~reflect & ui::Transform::ROT_180; - } - - return static_cast((rotate90 ^ inverseRotate90) | - (reflect ^ inverseReflect)); - } - - const sp mDisplay; - const Rect mSourceCrop; - const bool mAllowSecureLayers; - const ui::Transform mTransform = ui::Transform(); -}; - } // namespace android diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp new file mode 100644 index 0000000000..7cd283d3bb --- /dev/null +++ b/services/surfaceflinger/DisplayRenderArea.cpp @@ -0,0 +1,154 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DisplayRenderArea.h" +#include "DisplayDevice.h" + +namespace android { +namespace { + +RenderArea::RotationFlags applyDeviceOrientation(RenderArea::RotationFlags rotation, + const DisplayDevice& display) { + uint32_t inverseRotate90 = 0; + uint32_t inverseReflect = 0; + + // Reverse the logical orientation. + ui::Rotation logicalOrientation = display.getOrientation(); + if (logicalOrientation == ui::Rotation::Rotation90) { + logicalOrientation = ui::Rotation::Rotation270; + } else if (logicalOrientation == ui::Rotation::Rotation270) { + logicalOrientation = ui::Rotation::Rotation90; + } + + const ui::Rotation orientation = display.getPhysicalOrientation() + logicalOrientation; + + switch (orientation) { + case ui::ROTATION_0: + return rotation; + + case ui::ROTATION_90: + inverseRotate90 = ui::Transform::ROT_90; + inverseReflect = ui::Transform::ROT_180; + break; + + case ui::ROTATION_180: + inverseReflect = ui::Transform::ROT_180; + break; + + case ui::ROTATION_270: + inverseRotate90 = ui::Transform::ROT_90; + break; + } + + const uint32_t rotate90 = rotation & ui::Transform::ROT_90; + uint32_t reflect = rotation & ui::Transform::ROT_180; + + // Apply reflection for double rotation. + if (rotate90 & inverseRotate90) { + reflect = ~reflect & ui::Transform::ROT_180; + } + + return static_cast((rotate90 ^ inverseRotate90) | + (reflect ^ inverseReflect)); +} + +} // namespace + +std::unique_ptr DisplayRenderArea::create(wp displayWeak, + const Rect& sourceCrop, ui::Size reqSize, + ui::Dataspace reqDataSpace, + RotationFlags rotation, + bool allowSecureLayers) { + if (auto display = displayWeak.promote()) { + // Using new to access a private constructor. + return std::unique_ptr( + new DisplayRenderArea(std::move(display), sourceCrop, reqSize, reqDataSpace, + rotation, allowSecureLayers)); + } + return nullptr; +} + +DisplayRenderArea::DisplayRenderArea(sp display, const Rect& sourceCrop, + ui::Size reqSize, ui::Dataspace reqDataSpace, + RotationFlags rotation, bool allowSecureLayers) + : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, display->getViewport(), + applyDeviceOrientation(rotation, *display)), + mDisplay(std::move(display)), + mSourceCrop(sourceCrop), + mAllowSecureLayers(allowSecureLayers) {} + +const ui::Transform& DisplayRenderArea::getTransform() const { + return mTransform; +} + +Rect DisplayRenderArea::getBounds() const { + return mDisplay->getBounds(); +} + +int DisplayRenderArea::getHeight() const { + return mDisplay->getHeight(); +} + +int DisplayRenderArea::getWidth() const { + return mDisplay->getWidth(); +} + +bool DisplayRenderArea::isSecure() const { + return mAllowSecureLayers && mDisplay->isSecure(); +} + +sp DisplayRenderArea::getDisplayDevice() const { + return mDisplay; +} + +bool DisplayRenderArea::needsFiltering() const { + // check if the projection from the logical render area + // to the physical render area requires filtering + const Rect& sourceCrop = getSourceCrop(); + int width = sourceCrop.width(); + int height = sourceCrop.height(); + if (getRotationFlags() & ui::Transform::ROT_90) { + std::swap(width, height); + } + return width != getReqWidth() || height != getReqHeight(); +} + +Rect DisplayRenderArea::getSourceCrop() const { + // use the projected display viewport by default. + if (mSourceCrop.isEmpty()) { + return mDisplay->getSourceClip(); + } + + // If there is a source crop provided then it is assumed that the device + // was in portrait orientation. This may not logically be true, so + // correct for the orientation error by undoing the rotation + + ui::Rotation logicalOrientation = mDisplay->getOrientation(); + if (logicalOrientation == ui::Rotation::Rotation90) { + logicalOrientation = ui::Rotation::Rotation270; + } else if (logicalOrientation == ui::Rotation::Rotation270) { + logicalOrientation = ui::Rotation::Rotation90; + } + + const auto flags = ui::Transform::toRotationFlags(logicalOrientation); + int width = mDisplay->getSourceClip().getWidth(); + int height = mDisplay->getSourceClip().getHeight(); + ui::Transform rotation; + rotation.set(flags, width, height); + return rotation.transform(mSourceCrop); +} + +} // namespace android \ No newline at end of file diff --git a/services/surfaceflinger/DisplayRenderArea.h b/services/surfaceflinger/DisplayRenderArea.h new file mode 100644 index 0000000000..340efb566f --- /dev/null +++ b/services/surfaceflinger/DisplayRenderArea.h @@ -0,0 +1,54 @@ +/* + * Copyright 2020 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 +#include + +#include "RenderArea.h" + +namespace android { + +class DisplayDevice; + +class DisplayRenderArea : public RenderArea { +public: + static std::unique_ptr create(wp, const Rect& sourceCrop, + ui::Size reqSize, ui::Dataspace, + RotationFlags rotation, + bool allowSecureLayers = true); + + const ui::Transform& getTransform() const override; + Rect getBounds() const override; + int getHeight() const override; + int getWidth() const override; + bool isSecure() const override; + sp getDisplayDevice() const override; + bool needsFiltering() const override; + Rect getSourceCrop() const override; + +private: + DisplayRenderArea(sp, const Rect& sourceCrop, ui::Size reqSize, + ui::Dataspace, RotationFlags rotation, bool allowSecureLayers = true); + + const sp mDisplay; + const Rect mSourceCrop; + const bool mAllowSecureLayers; + const ui::Transform mTransform; +}; + +} // namespace android \ No newline at end of file diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp new file mode 100644 index 0000000000..c4f8666de5 --- /dev/null +++ b/services/surfaceflinger/LayerRenderArea.cpp @@ -0,0 +1,113 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "ContainerLayer.h" +#include "DisplayDevice.h" +#include "Layer.h" +#include "LayerRenderArea.h" +#include "SurfaceFlinger.h" + +namespace android { +namespace { + +struct ReparentForDrawing { + const sp& oldParent; + + ReparentForDrawing(const sp& oldParent, const sp& newParent, + const Rect& drawingBounds) + : oldParent(oldParent) { + // Compute and cache the bounds for the new parent layer. + newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform(), + 0.f /* shadowRadius */); + oldParent->setChildrenDrawingParent(newParent); + } + ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); } +}; + +} // namespace + +LayerRenderArea::LayerRenderArea(SurfaceFlinger& flinger, sp layer, const Rect& crop, + ui::Size reqSize, ui::Dataspace reqDataSpace, bool childrenOnly, + const Rect& displayViewport) + : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, displayViewport), + mLayer(std::move(layer)), + mCrop(crop), + mFlinger(flinger), + mChildrenOnly(childrenOnly) {} + +const ui::Transform& LayerRenderArea::getTransform() const { + return mTransform; +} + +Rect LayerRenderArea::getBounds() const { + return mLayer->getBufferSize(mLayer->getDrawingState()); +} + +int LayerRenderArea::getHeight() const { + return mLayer->getBufferSize(mLayer->getDrawingState()).getHeight(); +} + +int LayerRenderArea::getWidth() const { + return mLayer->getBufferSize(mLayer->getDrawingState()).getWidth(); +} + +bool LayerRenderArea::isSecure() const { + return false; +} + +bool LayerRenderArea::needsFiltering() const { + return mNeedsFiltering; +} + +sp LayerRenderArea::getDisplayDevice() const { + return nullptr; +} + +Rect LayerRenderArea::getSourceCrop() const { + if (mCrop.isEmpty()) { + return getBounds(); + } else { + return mCrop; + } +} + +void LayerRenderArea::render(std::function drawLayers) { + using namespace std::string_literals; + + const Rect sourceCrop = getSourceCrop(); + // no need to check rotation because there is none + mNeedsFiltering = sourceCrop.width() != getReqWidth() || sourceCrop.height() != getReqHeight(); + + if (!mChildrenOnly) { + mTransform = mLayer->getTransform().inverse(); + drawLayers(); + } else { + uint32_t w = static_cast(getWidth()); + uint32_t h = static_cast(getHeight()); + // In the "childrenOnly" case we reparent the children to a screenshot + // layer which has no properties set and which does not draw. + sp screenshotParentLayer = mFlinger.getFactory().createContainerLayer( + {&mFlinger, nullptr, "Screenshot Parent"s, w, h, 0, LayerMetadata()}); + + ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop); + drawLayers(); + } +} + +} // namespace android diff --git a/services/surfaceflinger/LayerRenderArea.h b/services/surfaceflinger/LayerRenderArea.h new file mode 100644 index 0000000000..81690b9a7e --- /dev/null +++ b/services/surfaceflinger/LayerRenderArea.h @@ -0,0 +1,60 @@ +/* + * Copyright 2020 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 + +#include +#include +#include + +#include "RenderArea.h" + +namespace android { + +class DisplayDevice; +class Layer; +class SurfaceFlinger; + +class LayerRenderArea : public RenderArea { +public: + LayerRenderArea(SurfaceFlinger& flinger, sp layer, const Rect& crop, ui::Size reqSize, + ui::Dataspace reqDataSpace, bool childrenOnly, const Rect& displayViewport); + + const ui::Transform& getTransform() const override; + Rect getBounds() const override; + int getHeight() const override; + int getWidth() const override; + bool isSecure() const override; + bool needsFiltering() const override; + sp getDisplayDevice() const override; + Rect getSourceCrop() const override; + + void render(std::function drawLayers) override; + +private: + const sp mLayer; + const Rect mCrop; + + ui::Transform mTransform; + bool mNeedsFiltering = false; + + SurfaceFlinger& mFlinger; + const bool mChildrenOnly; +}; + +} // namespace android \ No newline at end of file diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 398fd40442..899d1fa024 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -35,6 +35,7 @@ #include #include "DisplayDevice.h" +#include "DisplayRenderArea.h" #include "Layer.h" #include "Promise.h" #include "Scheduler/DispSync.h" @@ -383,8 +384,9 @@ void RegionSamplingThread::captureSample() { const Rect sampledBounds = sampleRegion.bounds(); SurfaceFlinger::RenderAreaFuture renderAreaFuture = promise::defer([=] { - return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(), - ui::Dataspace::V0_SRGB, orientation); + return DisplayRenderArea::create(displayWeak, screencapRegion.bounds(), + sampledBounds.getSize(), ui::Dataspace::V0_SRGB, + orientation); }); std::unordered_set, SpHash> listeners; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9fd0f656a4..0e2e80ed6a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -101,10 +101,12 @@ #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/VirtualDisplaySurface.h" +#include "DisplayRenderArea.h" #include "EffectLayer.h" #include "Effects/Daltonizer.h" #include "FrameTracer/FrameTracer.h" #include "Layer.h" +#include "LayerRenderArea.h" #include "LayerVector.h" #include "MonitoredProducer.h" #include "NativeWindowSurface.h" @@ -5527,86 +5529,6 @@ status_t SurfaceFlinger::captureLayers( float frameScale, bool childrenOnly) { ATRACE_CALL(); - class LayerRenderArea : public RenderArea { - public: - LayerRenderArea(SurfaceFlinger* flinger, const sp& layer, const Rect crop, - ui::Size reqSize, Dataspace reqDataSpace, bool childrenOnly, - const Rect& displayViewport) - : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, displayViewport), - mLayer(layer), - mCrop(crop), - mNeedsFiltering(false), - mFlinger(flinger), - mChildrenOnly(childrenOnly) {} - const ui::Transform& getTransform() const override { return mTransform; } - Rect getBounds() const override { return mLayer->getBufferSize(mLayer->getDrawingState()); } - int getHeight() const override { - return mLayer->getBufferSize(mLayer->getDrawingState()).getHeight(); - } - int getWidth() const override { - return mLayer->getBufferSize(mLayer->getDrawingState()).getWidth(); - } - bool isSecure() const override { return false; } - bool needsFiltering() const override { return mNeedsFiltering; } - sp getDisplayDevice() const override { return nullptr; } - Rect getSourceCrop() const override { - if (mCrop.isEmpty()) { - return getBounds(); - } else { - return mCrop; - } - } - class ReparentForDrawing { - public: - const sp& oldParent; - const sp& newParent; - - ReparentForDrawing(const sp& oldParent, const sp& newParent, - const Rect& drawingBounds) - : oldParent(oldParent), newParent(newParent) { - // Compute and cache the bounds for the new parent layer. - newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform(), - 0.f /* shadowRadius */); - oldParent->setChildrenDrawingParent(newParent); - } - ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); } - }; - - void render(std::function drawLayers) override { - const Rect sourceCrop = getSourceCrop(); - // no need to check rotation because there is none - mNeedsFiltering = sourceCrop.width() != getReqWidth() || - sourceCrop.height() != getReqHeight(); - - if (!mChildrenOnly) { - mTransform = mLayer->getTransform().inverse(); - drawLayers(); - } else { - uint32_t w = static_cast(getWidth()); - uint32_t h = static_cast(getHeight()); - // In the "childrenOnly" case we reparent the children to a screenshot - // layer which has no properties set and which does not draw. - sp screenshotParentLayer = - mFlinger->getFactory().createContainerLayer({mFlinger, nullptr, - "Screenshot Parent"s, w, h, 0, - LayerMetadata()}); - - ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop); - drawLayers(); - } - } - - private: - const sp mLayer; - const Rect mCrop; - - ui::Transform mTransform; - bool mNeedsFiltering; - - SurfaceFlinger* mFlinger; - const bool mChildrenOnly; - }; - ui::Size reqSize; sp parent; Rect crop(sourceCrop); @@ -5673,7 +5595,7 @@ status_t SurfaceFlinger::captureLayers( } RenderAreaFuture renderAreaFuture = promise::defer([=]() -> std::unique_ptr { - return std::make_unique(this, parent, crop, reqSize, reqDataspace, + return std::make_unique(*this, parent, crop, reqSize, reqDataspace, childrenOnly, displayViewport); }); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 35648ceb65..1fbe99fae0 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -95,6 +95,7 @@ class Layer; class MessageBase; class RefreshRateOverlay; class RegionSamplingThread; +class RenderArea; class TimeStats; class FrameTracer; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 456891e11f..9355e61491 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -35,6 +35,7 @@ #include #include "BufferQueueLayer.h" +#include "DisplayRenderArea.h" #include "EffectLayer.h" #include "Layer.h" #include "TestableSurfaceFlinger.h" @@ -248,8 +249,9 @@ void CompositionTest::captureScreenComposition() { int fd = -1; status_t result = - mFlinger.captureScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer.get(), - useIdentityTransform, forSystem, &fd, regionSampling); + mFlinger.captureScreenImplLocked(*renderArea, traverseLayers, + mCaptureScreenBuffer.get(), useIdentityTransform, + forSystem, &fd, regionSampling); if (fd >= 0) { close(fd); } -- cgit v1.2.3-59-g8ed1b From 426b5c0cab15cacf94206dd3c879d30fa0a26670 Mon Sep 17 00:00:00 2001 From: chaviw Date: Mon, 27 Jul 2020 11:20:15 -0700 Subject: Use ScreenCaptureResults in screenCapture helper functions It makes more sense to directly send the ScreenCaptureResults object to the screenCapture helper functions so the render function can populate the results. This makes it easier when adding new result values since they likely want to be set for any screenshot path request. Currently, the result object contains the buffer, whether secure layers were captured, and the dataspace it was captured in. Test: SurfaceFlinger_test Bug: 162367424 Change-Id: I3b1f5264051bb2e885ce0d0df0cd18c8f55afdd1 --- services/surfaceflinger/RegionSamplingThread.cpp | 5 +- services/surfaceflinger/SurfaceFlinger.cpp | 92 ++++++++++------------ services/surfaceflinger/SurfaceFlinger.h | 20 +++-- .../tests/unittests/CompositionTest.cpp | 5 +- .../tests/unittests/TestableSurfaceFlinger.h | 16 ++-- 5 files changed, 62 insertions(+), 76 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 899d1fa024..17daadba02 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -442,9 +442,10 @@ void RegionSamplingThread::captureSample() { PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); } - bool ignored; + ScreenCaptureResults captureResults; mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - false /* identityTransform */, true /* regionSampling */, ignored); + false /* identityTransform */, true /* regionSampling */, + captureResults); std::vector activeDescriptors; for (const auto& descriptor : descriptors) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8823716191..0d9080d60d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5482,11 +5482,8 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) { traverseLayersInLayerStack(layerStack, visitor); }; - - captureResults.capturedDataspace = dataspace; return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - &captureResults.buffer, args.pixelFormat, args.useIdentityTransform, - captureResults.capturedSecureLayers); + args.pixelFormat, args.useIdentityTransform, captureResults); } status_t SurfaceFlinger::setSchedFifo(bool enabled) { @@ -5534,6 +5531,7 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, wp displayWeak; ui::Size size; ui::Transform::RotationFlags captureOrientation; + ui::Dataspace dataspace; { Mutex::Autolock lock(mStateLock); sp display = getDisplayByIdOrLayerStack(displayOrLayerStack); @@ -5565,7 +5563,7 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, default: break; } - captureResults.capturedDataspace = + dataspace = pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode); } @@ -5580,9 +5578,8 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, }; return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, - &captureResults.buffer, ui::PixelFormat::RGBA_8888, - false /* useIdentityTransform */, - captureResults.capturedSecureLayers); + ui::PixelFormat::RGBA_8888, false /* useIdentityTransform */, + captureResults); } status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, @@ -5686,37 +5683,34 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, }); }; - captureResults.capturedDataspace = dataspace; return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - &captureResults.buffer, args.pixelFormat, false, - captureResults.capturedSecureLayers); + args.pixelFormat, false, captureResults); } status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, - ui::Size bufferSize, sp* outBuffer, - ui::PixelFormat reqPixelFormat, + ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool useIdentityTransform, - bool& outCapturedSecureLayers) { + ScreenCaptureResults& captureResults) { ATRACE_CALL(); // TODO(b/116112787) Make buffer usage a parameter. const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - *outBuffer = getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(), - static_cast(reqPixelFormat), - 1, usage, "screenshot"); + sp buffer = + getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(), + static_cast(reqPixelFormat), + 1 /* layerCount */, usage, "screenshot"); - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, *outBuffer, - useIdentityTransform, false /* regionSampling */, - outCapturedSecureLayers); + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, + useIdentityTransform, false /* regionSampling */, captureResults); } status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, const sp& buffer, bool useIdentityTransform, bool regionSampling, - bool& outCapturedSecureLayers) { + ScreenCaptureResults& captureResults) { const int uid = IPCThreadState::self()->getCallingUid(); const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM; @@ -5741,9 +5735,9 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, Mutex::Autolock lock(mStateLock); renderArea->render([&] { - result = captureScreenImplLocked(*renderArea, traverseLayers, buffer.get(), - useIdentityTransform, forSystem, &fd, - regionSampling, outCapturedSecureLayers); + result = renderScreenImplLocked(*renderArea, traverseLayers, buffer.get(), + useIdentityTransform, forSystem, &fd, + regionSampling, captureResults); }); return {result, fd}; @@ -5758,13 +5752,30 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, return result; } -void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, - TraverseLayersFunction traverseLayers, - const sp& buffer, - bool useIdentityTransform, bool regionSampling, - int* outSyncFd) { +status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, + TraverseLayersFunction traverseLayers, + const sp& buffer, + bool useIdentityTransform, bool forSystem, + int* outSyncFd, bool regionSampling, + ScreenCaptureResults& captureResults) { ATRACE_CALL(); + traverseLayers([&](Layer* layer) { + captureResults.capturedSecureLayers = + captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure()); + }); + + // We allow the system server to take screenshots of secure layers for + // use in situations like the Screen-rotation animation and place + // the impetus on WindowManager to not persist them. + if (captureResults.capturedSecureLayers && !forSystem) { + ALOGW("FB is protected: PERMISSION_DENIED"); + return PERMISSION_DENIED; + } + + captureResults.buffer = buffer; + captureResults.capturedDataspace = renderArea.getReqDataSpace(); + const auto reqWidth = renderArea.getReqWidth(); const auto reqHeight = renderArea.getReqHeight(); const auto sourceCrop = renderArea.getSourceCrop(); @@ -5856,30 +5867,7 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, layer->onLayerDisplayed(releaseFence); } } -} - -status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea, - TraverseLayersFunction traverseLayers, - const sp& buffer, - bool useIdentityTransform, bool forSystem, - int* outSyncFd, bool regionSampling, - bool& outCapturedSecureLayers) { - ATRACE_CALL(); - - traverseLayers([&](Layer* layer) { - outCapturedSecureLayers = - outCapturedSecureLayers || (layer->isVisible() && layer->isSecure()); - }); - // We allow the system server to take screenshots of secure layers for - // use in situations like the Screen-rotation animation and place - // the impetus on WindowManager to not persist them. - if (outCapturedSecureLayers && !forSystem) { - ALOGW("FB is protected: PERMISSION_DENIED"); - return PERMISSION_DENIED; - } - renderScreenImplLocked(renderArea, traverseLayers, buffer, useIdentityTransform, regionSampling, - outSyncFd); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c933d740f8..2552a01962 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -719,22 +719,20 @@ private: using TraverseLayersFunction = std::function; using RenderAreaFuture = std::future>; - void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, - const sp& buffer, bool useIdentityTransform, - bool regionSampling, int* outSyncFd); + status_t renderScreenImplLocked(const RenderArea& renderArea, + TraverseLayersFunction traverseLayers, + const sp& buffer, bool useIdentityTransform, + bool forSystem, int* outSyncFd, bool regionSampling, + ScreenCaptureResults& captureResults); status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, - sp* outBuffer, ui::PixelFormat, - bool useIdentityTransform, bool& outCapturedSecureLayers); + ui::PixelFormat, bool useIdentityTransform, + ScreenCaptureResults& captureResults); status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, const sp&, bool useIdentityTransform, bool regionSampling, - bool& outCapturedSecureLayers); + ScreenCaptureResults& captureResults); sp getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); sp getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock); - status_t captureScreenImplLocked(const RenderArea& renderArea, - TraverseLayersFunction traverseLayers, - const sp& buffer, bool useIdentityTransform, - bool forSystem, int* outSyncFd, bool regionSampling, - bool& outCapturedSecureLayers); + void traverseLayersInLayerStack(ui::LayerStack, const LayerVector::Visitor&); sp mStartPropertySetThread; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 9add6a52af..9959ef6f22 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -254,9 +254,8 @@ void CompositionTest::captureScreenComposition() { int fd = -1; status_t result = - mFlinger.captureScreenImplLocked(*renderArea, traverseLayers, - mCaptureScreenBuffer.get(), useIdentityTransform, - forSystem, &fd, regionSampling); + mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer.get(), + useIdentityTransform, forSystem, &fd, regionSampling); if (fd >= 0) { close(fd); } diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 256e048fee..7489d705f6 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -339,14 +339,14 @@ public: auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what, systemTime()); } - auto captureScreenImplLocked(const RenderArea& renderArea, - SurfaceFlinger::TraverseLayersFunction traverseLayers, - const sp& buffer, bool useIdentityTransform, - bool forSystem, int* outSyncFd, bool regionSampling) { - bool ignored; - return mFlinger->captureScreenImplLocked(renderArea, traverseLayers, buffer, - useIdentityTransform, forSystem, outSyncFd, - regionSampling, ignored); + auto renderScreenImplLocked(const RenderArea& renderArea, + SurfaceFlinger::TraverseLayersFunction traverseLayers, + const sp& buffer, bool useIdentityTransform, + bool forSystem, int* outSyncFd, bool regionSampling) { + ScreenCaptureResults captureResults; + return mFlinger->renderScreenImplLocked(renderArea, traverseLayers, buffer, + useIdentityTransform, forSystem, outSyncFd, + regionSampling, captureResults); } auto traverseLayersInLayerStack(ui::LayerStack layerStack, -- cgit v1.2.3-59-g8ed1b From c6ad8afa768607852a1ad2c937b4687e947d6fca Mon Sep 17 00:00:00 2001 From: chaviw Date: Mon, 3 Aug 2020 11:33:30 -0700 Subject: Remove rotation and use flag useIdentityTransform for screenshots. There's a lot of confusing logic where 90 and 270 rotation values need to be flipped to ensure the screenshot is taken the correct orientation. There's also confusion what useIdentityTransform means, especially if a non 0 rotation value is sent. The cases screenshot cares about is the following: 1. Take screenshot in current display orientation 2. Take screenshot with 0 rotation so the caller can handle rotating the screenshot themselves. With these two cases in mind, remove the rotation value passed in for screenshots. If useIdentityTransform is true, it will rotate the screenshot so it's in the 0 orientation. If useIdentityTransform is false, it will use the current display rotation. This simplifies the logic in DisplayRenderArea since it only needs to compute the rotation when useIdentityTransform is set. It also simplifies the caller logic since they no longer have to find the current display rotation to ensure the screenshot is taken in the current rotation. The callers can just request the screenshot with useIdentityTransform set to false. Test: adb shell screencap Test: Power + volume screenshot Test: Screen rotation Test: SurfaceFlinger_test Test: libsurfaceflinger_unittest Fixes: 135942984 Change-Id: I1da025c7340a11a719d4630da2469b281bddc6e9 --- libs/gui/LayerState.cpp | 10 +--- libs/gui/include/gui/LayerState.h | 1 - .../include/compositionengine/LayerFE.h | 6 -- .../CompositionEngine/src/Output.cpp | 2 - .../CompositionEngine/tests/OutputTest.cpp | 21 ------- services/surfaceflinger/DisplayRenderArea.cpp | 70 +++++----------------- services/surfaceflinger/DisplayRenderArea.h | 4 +- services/surfaceflinger/Layer.cpp | 8 +-- services/surfaceflinger/RegionSamplingThread.cpp | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 53 ++++------------ services/surfaceflinger/SurfaceFlinger.h | 11 ++-- services/surfaceflinger/tests/LayerState_test.cpp | 2 - .../tests/unittests/CompositionTest.cpp | 3 +- .../tests/unittests/TestableSurfaceFlinger.h | 9 ++- 14 files changed, 41 insertions(+), 162 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index b215756d56..9c0ad9d4e5 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -530,23 +530,17 @@ status_t DisplayCaptureArgs::write(Parcel& output) const { status |= output.writeStrongBinder(displayToken) ?: output.writeUint32(width) ?: output.writeUint32(height) ?: - output.writeBool(useIdentityTransform) ?: - output.writeInt32(static_cast(rotation)); + output.writeBool(useIdentityTransform); return status; } status_t DisplayCaptureArgs::read(const Parcel& input) { status_t status = CaptureArgs::read(input); - int32_t rotationInt = 0; - status |= input.readStrongBinder(&displayToken) ?: input.readUint32(&width) ?: input.readUint32(&height) ?: - input.readBool(&useIdentityTransform) ?: - input.readInt32(&rotationInt); - - rotation = ui::toRotation(rotationInt); + input.readBool(&useIdentityTransform); return status; } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 5e1066ba68..bbf827f0cd 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -330,7 +330,6 @@ struct DisplayCaptureArgs : CaptureArgs { uint32_t width{0}; uint32_t height{0}; bool useIdentityTransform{false}; - ui::Rotation rotation{ui::ROTATION_0}; status_t write(Parcel& output) const override; status_t read(const Parcel& input) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 6cc90cb3ee..5c7f12dd3d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -80,10 +80,6 @@ public: // The clip region, or visible region that is being rendered to const Region& clip; - // If true, the layer should use an identity transform for its position - // transform. Used only by the captureScreen API call. - const bool useIdentityTransform; - // If set to true, the layer should enable filtering when rendering. const bool needsFiltering; @@ -148,7 +144,6 @@ using LayerFESet = std::unordered_set, LayerFESpHash>; static inline bool operator==(const LayerFE::ClientCompositionTargetSettings& lhs, const LayerFE::ClientCompositionTargetSettings& rhs) { return lhs.clip.hasSameRects(rhs.clip) && - lhs.useIdentityTransform == rhs.useIdentityTransform && lhs.needsFiltering == rhs.needsFiltering && lhs.isSecure == rhs.isSecure && lhs.supportsProtectedContent == rhs.supportsProtectedContent && lhs.clearRegion.hasSameRects(rhs.clearRegion) && lhs.viewport == rhs.viewport && @@ -170,7 +165,6 @@ static inline void PrintTo(const LayerFE::ClientCompositionTargetSettings& setti *os << "ClientCompositionTargetSettings{"; *os << "\n .clip = \n"; PrintTo(settings.clip, os); - *os << "\n .useIdentityTransform = " << settings.useIdentityTransform; *os << "\n .needsFiltering = " << settings.needsFiltering; *os << "\n .isSecure = " << settings.isSecure; *os << "\n .supportsProtectedContent = " << settings.supportsProtectedContent; diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 09b3dd7053..670b969e17 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -946,7 +946,6 @@ std::vector Output::generateClientCompositionRequests( const auto& outputState = getState(); const Region viewportRegion(outputState.viewport); - const bool useIdentityTransform = false; bool firstLayer = true; // Used when a layer clears part of the buffer. Region stubRegion; @@ -984,7 +983,6 @@ std::vector Output::generateClientCompositionRequests( if (clientComposition || clearClientComposition) { compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ clip, - useIdentityTransform, layer->needsFiltering() || outputState.needsFiltering, outputState.isSecure, supportsProtectedContent, diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 6ba06a632c..fdaf907e8a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -3579,7 +3579,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqu compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ @@ -3591,7 +3590,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqu }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ @@ -3635,7 +3633,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, compositionengine::LayerFE::ClientCompositionTargetSettings layer0TargetSettings{ Region(Rect(10, 10, 20, 20)), - false, /* identity transform */ false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ @@ -3647,7 +3644,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(Rect(0, 0, 30, 30)), - false, /* identity transform */ false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ @@ -3659,7 +3655,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(Rect(0, 0, 40, 201)), - false, /* identity transform */ false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ @@ -3691,7 +3686,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, compositionengine::LayerFE::ClientCompositionTargetSettings layer0TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ true, /* needs filtering */ false, /* secure */ false, /* supports protected content */ @@ -3703,7 +3697,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ @@ -3715,7 +3708,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ @@ -3747,7 +3739,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, compositionengine::LayerFE::ClientCompositionTargetSettings layer0TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ true, /* needs filtering */ false, /* secure */ false, /* supports protected content */ @@ -3760,7 +3751,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ true, /* needs filtering */ false, /* secure */ false, /* supports protected content */ @@ -3772,7 +3762,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ true, /* needs filtering */ false, /* secure */ false, /* supports protected content */ @@ -3803,7 +3792,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, compositionengine::LayerFE::ClientCompositionTargetSettings layer0TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ false, /* needs filtering */ true, /* secure */ false, /* supports protected content */ @@ -3815,7 +3803,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ false, /* needs filtering */ true, /* secure */ false, /* supports protected content */ @@ -3827,7 +3814,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ false, /* needs filtering */ true, /* secure */ false, /* supports protected content */ @@ -3856,7 +3842,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, compositionengine::LayerFE::ClientCompositionTargetSettings layer0TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ false, /* needs filtering */ false, /* secure */ true, /* supports protected content */ @@ -3868,7 +3853,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ false, /* needs filtering */ false, /* secure */ true, /* supports protected content */ @@ -3880,7 +3864,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), - false, /* identity transform */ false, /* needs filtering */ false, /* secure */ true, /* supports protected content */ @@ -3972,7 +3955,6 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq compositionengine::LayerFE::ClientCompositionTargetSettings leftLayerSettings{ Region(Rect(0, 0, 1000, 1000)), - false, /* identity transform */ false, /* needs filtering */ true, /* secure */ true, /* supports protected content */ @@ -3990,7 +3972,6 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq compositionengine::LayerFE::ClientCompositionTargetSettings rightLayerSettings{ Region(Rect(1000, 0, 2000, 1000)), - false, /* identity transform */ false, /* needs filtering */ true, /* secure */ true, /* supports protected content */ @@ -4024,7 +4005,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, Region accumClearRegion(Rect(10, 11, 12, 13)); compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{ Region(Rect(60, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */ - false, /* identity transform */ false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ @@ -4070,7 +4050,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, Region accumClearRegion(Rect(10, 11, 12, 13)); compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{ Region(Rect(50, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */ - false, /* identity transform */ false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp index 4bae669d7c..d7157b1607 100644 --- a/services/surfaceflinger/DisplayRenderArea.cpp +++ b/services/surfaceflinger/DisplayRenderArea.cpp @@ -20,49 +20,14 @@ namespace android { namespace { -RenderArea::RotationFlags applyDeviceOrientation(RenderArea::RotationFlags rotation, +RenderArea::RotationFlags applyDeviceOrientation(bool useIdentityTransform, const DisplayDevice& display) { - uint32_t inverseRotate90 = 0; - uint32_t inverseReflect = 0; - - // Reverse the logical orientation. - ui::Rotation logicalOrientation = display.getOrientation(); - if (logicalOrientation == ui::Rotation::Rotation90) { - logicalOrientation = ui::Rotation::Rotation270; - } else if (logicalOrientation == ui::Rotation::Rotation270) { - logicalOrientation = ui::Rotation::Rotation90; + if (!useIdentityTransform) { + return RenderArea::RotationFlags::ROT_0; } - const ui::Rotation orientation = display.getPhysicalOrientation() + logicalOrientation; - - switch (orientation) { - case ui::ROTATION_0: - return rotation; - - case ui::ROTATION_90: - inverseRotate90 = ui::Transform::ROT_90; - inverseReflect = ui::Transform::ROT_180; - break; - - case ui::ROTATION_180: - inverseReflect = ui::Transform::ROT_180; - break; - - case ui::ROTATION_270: - inverseRotate90 = ui::Transform::ROT_90; - break; - } - - const uint32_t rotate90 = rotation & ui::Transform::ROT_90; - uint32_t reflect = rotation & ui::Transform::ROT_180; - - // Apply reflection for double rotation. - if (rotate90 & inverseRotate90) { - reflect = ~reflect & ui::Transform::ROT_180; - } - - return static_cast((rotate90 ^ inverseRotate90) | - (reflect ^ inverseReflect)); + const ui::Rotation orientation = display.getPhysicalOrientation() + display.getOrientation(); + return ui::Transform::toRotationFlags(orientation); } } // namespace @@ -70,22 +35,22 @@ RenderArea::RotationFlags applyDeviceOrientation(RenderArea::RotationFlags rotat std::unique_ptr DisplayRenderArea::create(wp displayWeak, const Rect& sourceCrop, ui::Size reqSize, ui::Dataspace reqDataSpace, - RotationFlags rotation, + bool useIdentityTransform, bool allowSecureLayers) { if (auto display = displayWeak.promote()) { // Using new to access a private constructor. return std::unique_ptr( new DisplayRenderArea(std::move(display), sourceCrop, reqSize, reqDataSpace, - rotation, allowSecureLayers)); + useIdentityTransform, allowSecureLayers)); } return nullptr; } DisplayRenderArea::DisplayRenderArea(sp display, const Rect& sourceCrop, ui::Size reqSize, ui::Dataspace reqDataSpace, - RotationFlags rotation, bool allowSecureLayers) + bool useIdentityTransform, bool allowSecureLayers) : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, display->getViewport(), - allowSecureLayers, applyDeviceOrientation(rotation, *display)), + allowSecureLayers, applyDeviceOrientation(useIdentityTransform, *display)), mDisplay(std::move(display)), mSourceCrop(sourceCrop) {} @@ -131,18 +96,11 @@ Rect DisplayRenderArea::getSourceCrop() const { return mDisplay->getViewport(); } - // If there is a source crop provided then it is assumed that the device - // was in portrait orientation. This may not logically be true, so - // correct for the orientation error by undoing the rotation - - ui::Rotation logicalOrientation = mDisplay->getOrientation(); - if (logicalOrientation == ui::Rotation::Rotation90) { - logicalOrientation = ui::Rotation::Rotation270; - } else if (logicalOrientation == ui::Rotation::Rotation270) { - logicalOrientation = ui::Rotation::Rotation90; - } - - const auto flags = ui::Transform::toRotationFlags(logicalOrientation); + // Correct for the orientation when the screen capture request contained + // useIdentityTransform. This will cause the rotation flag to be non 0 since + // it needs to rotate based on the screen orientation to allow the screenshot + // to be taken in the ROT_0 orientation + const auto flags = getRotationFlags(); int width = mDisplay->getViewport().getWidth(); int height = mDisplay->getViewport().getHeight(); ui::Transform rotation; diff --git a/services/surfaceflinger/DisplayRenderArea.h b/services/surfaceflinger/DisplayRenderArea.h index 8840973a5a..3478fc16c4 100644 --- a/services/surfaceflinger/DisplayRenderArea.h +++ b/services/surfaceflinger/DisplayRenderArea.h @@ -29,7 +29,7 @@ class DisplayRenderArea : public RenderArea { public: static std::unique_ptr create(wp, const Rect& sourceCrop, ui::Size reqSize, ui::Dataspace, - RotationFlags rotation, + bool useIdentityTransform, bool allowSecureLayers = true); const ui::Transform& getTransform() const override; @@ -43,7 +43,7 @@ public: private: DisplayRenderArea(sp, const Rect& sourceCrop, ui::Size reqSize, - ui::Dataspace, RotationFlags rotation, bool allowSecureLayers = true); + ui::Dataspace, bool useIdentityTransform, bool allowSecureLayers = true); const sp mDisplay; const Rect mSourceCrop; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 89c95d2846..001eab7f96 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -611,7 +611,7 @@ const char* Layer::getDebugName() const { // --------------------------------------------------------------------------- std::optional Layer::prepareClientComposition( - compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { + compositionengine::LayerFE::ClientCompositionTargetSettings& /* targetSettings */) { if (!getCompositionState()) { return {}; } @@ -621,11 +621,7 @@ std::optional Layer::prepareClientCom compositionengine::LayerFE::LayerSettings layerSettings; layerSettings.geometry.boundaries = bounds; - if (targetSettings.useIdentityTransform) { - layerSettings.geometry.positionTransform = mat4(); - } else { - layerSettings.geometry.positionTransform = getTransform().asMatrix4(); - } + layerSettings.geometry.positionTransform = getTransform().asMatrix4(); if (hasColorTransform()) { layerSettings.colorTransform = getColorTransform(); diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 17daadba02..255a1f2450 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -444,8 +444,7 @@ void RegionSamplingThread::captureSample() { ScreenCaptureResults captureResults; mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - false /* identityTransform */, true /* regionSampling */, - captureResults); + true /* regionSampling */, captureResults); std::vector activeDescriptors; for (const auto& descriptor : descriptors) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9d9a4cfdb0..9ff57df572 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5440,12 +5440,6 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, if (!args.displayToken) return BAD_VALUE; - auto renderAreaRotation = ui::Transform::toRotationFlags(args.rotation); - if (renderAreaRotation == ui::Transform::ROT_INVALID) { - ALOGE("%s: Invalid rotation: %s", __FUNCTION__, toCString(args.rotation)); - renderAreaRotation = ui::Transform::ROT_0; - } - wp displayWeak; ui::LayerStack layerStack; ui::Size reqSize(args.width, args.height); @@ -5469,14 +5463,14 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, RenderAreaFuture renderAreaFuture = promise::defer([=] { return DisplayRenderArea::create(displayWeak, args.sourceCrop, reqSize, dataspace, - renderAreaRotation, args.captureSecureLayers); + args.useIdentityTransform, args.captureSecureLayers); }); auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) { traverseLayersInLayerStack(layerStack, visitor); }; return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, args.useIdentityTransform, captureResults); + args.pixelFormat, captureResults); } status_t SurfaceFlinger::setSchedFifo(bool enabled) { @@ -5523,7 +5517,6 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, ui::LayerStack layerStack; wp displayWeak; ui::Size size; - ui::Transform::RotationFlags captureOrientation; ui::Dataspace dataspace; { Mutex::Autolock lock(mStateLock); @@ -5536,33 +5529,14 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, size = display->getViewport().getSize(); - const auto orientation = display->getOrientation(); - captureOrientation = ui::Transform::toRotationFlags(orientation); - - switch (captureOrientation) { - case ui::Transform::ROT_90: - captureOrientation = ui::Transform::ROT_270; - break; - - case ui::Transform::ROT_270: - captureOrientation = ui::Transform::ROT_90; - break; - - case ui::Transform::ROT_INVALID: - ALOGE("%s: Invalid orientation: %s", __FUNCTION__, toCString(orientation)); - captureOrientation = ui::Transform::ROT_0; - break; - - default: - break; - } dataspace = pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode); } RenderAreaFuture renderAreaFuture = promise::defer([=] { return DisplayRenderArea::create(displayWeak, Rect(), size, - captureResults.capturedDataspace, captureOrientation, + captureResults.capturedDataspace, + false /* useIdentityTransform */, false /* captureSecureLayers */); }); @@ -5571,8 +5545,7 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, }; return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, - ui::PixelFormat::RGBA_8888, false /* useIdentityTransform */, - captureResults); + ui::PixelFormat::RGBA_8888, captureResults); } status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, @@ -5681,13 +5654,12 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, }; return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, false, captureResults); + args.pixelFormat, captureResults); } status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, - bool useIdentityTransform, ScreenCaptureResults& captureResults) { ATRACE_CALL(); @@ -5700,13 +5672,12 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, 1 /* layerCount */, usage, "screenshot"); return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - useIdentityTransform, false /* regionSampling */, captureResults); + false /* regionSampling */, captureResults); } status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, - const sp& buffer, - bool useIdentityTransform, bool regionSampling, + const sp& buffer, bool regionSampling, ScreenCaptureResults& captureResults) { const int uid = IPCThreadState::self()->getCallingUid(); const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM; @@ -5733,8 +5704,8 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, Mutex::Autolock lock(mStateLock); renderArea->render([&] { result = renderScreenImplLocked(*renderArea, traverseLayers, buffer.get(), - useIdentityTransform, forSystem, &fd, - regionSampling, captureResults); + forSystem, &fd, regionSampling, + captureResults); }); return {result, fd}; @@ -5751,8 +5722,7 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, - const sp& buffer, - bool useIdentityTransform, bool forSystem, + const sp& buffer, bool forSystem, int* outSyncFd, bool regionSampling, ScreenCaptureResults& captureResults) { ATRACE_CALL(); @@ -5810,7 +5780,6 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, Region clip(renderArea.getBounds()); compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ clip, - useIdentityTransform, layer->needsFilteringForScreenshots(display.get(), transform) || renderArea.needsFiltering(), renderArea.isSecure(), diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6c00931941..2e85c1b85b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -719,15 +719,12 @@ private: status_t renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, - const sp& buffer, bool useIdentityTransform, - bool forSystem, int* outSyncFd, bool regionSampling, - ScreenCaptureResults& captureResults); + const sp& buffer, bool forSystem, int* outSyncFd, + bool regionSampling, ScreenCaptureResults& captureResults); status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, - ui::PixelFormat, bool useIdentityTransform, - ScreenCaptureResults& captureResults); + ui::PixelFormat, ScreenCaptureResults& captureResults); status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, const sp&, - bool useIdentityTransform, bool regionSampling, - ScreenCaptureResults& captureResults); + bool regionSampling, ScreenCaptureResults& captureResults); sp getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); sp getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock); diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp index 8a49e77848..785c2c3bc9 100644 --- a/services/surfaceflinger/tests/LayerState_test.cpp +++ b/services/surfaceflinger/tests/LayerState_test.cpp @@ -34,7 +34,6 @@ TEST(LayerStateTest, ParcellingDisplayCaptureArgs) { args.width = 10; args.height = 20; args.useIdentityTransform = true; - args.rotation = ui::ROTATION_90; Parcel p; args.write(p); @@ -51,7 +50,6 @@ TEST(LayerStateTest, ParcellingDisplayCaptureArgs) { ASSERT_EQ(args.width, args2.width); ASSERT_EQ(args.height, args2.height); ASSERT_EQ(args.useIdentityTransform, args2.useIdentityTransform); - ASSERT_EQ(args.rotation, args2.rotation); } TEST(LayerStateTest, ParcellingLayerCaptureArgs) { diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 48c4e18c62..6472428c55 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -233,7 +233,6 @@ void CompositionTest::captureScreenComposition() { LayerCase::setupForScreenCapture(this); const Rect sourceCrop(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT); - constexpr bool useIdentityTransform = true; constexpr bool forSystem = true; constexpr bool regionSampling = false; @@ -253,7 +252,7 @@ void CompositionTest::captureScreenComposition() { int fd = -1; status_t result = mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer.get(), - useIdentityTransform, forSystem, &fd, regionSampling); + forSystem, &fd, regionSampling); if (fd >= 0) { close(fd); } diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 3941d4218f..345577d387 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -335,12 +335,11 @@ public: auto renderScreenImplLocked(const RenderArea& renderArea, SurfaceFlinger::TraverseLayersFunction traverseLayers, - const sp& buffer, bool useIdentityTransform, - bool forSystem, int* outSyncFd, bool regionSampling) { + const sp& buffer, bool forSystem, int* outSyncFd, + bool regionSampling) { ScreenCaptureResults captureResults; - return mFlinger->renderScreenImplLocked(renderArea, traverseLayers, buffer, - useIdentityTransform, forSystem, outSyncFd, - regionSampling, captureResults); + return mFlinger->renderScreenImplLocked(renderArea, traverseLayers, buffer, forSystem, + outSyncFd, regionSampling, captureResults); } auto traverseLayersInLayerStack(ui::LayerStack layerStack, -- cgit v1.2.3-59-g8ed1b From 4b9d5e1c02dc053555497ec4c92d2e46146c53e2 Mon Sep 17 00:00:00 2001 From: chaviw Date: Tue, 4 Aug 2020 18:30:35 -0700 Subject: Allow screen capture for a specified uid. Currently, screenshots can either be done on the entire display or for a layer hierarchy. Screenshots can only be taken by a system process or a process with the correct permission. This change introduces a way for an app to screenshot itself without introducing security issues The following checks are done: 1. If the request is from graphics or has READ_FRAME_BUFFER permission flag, the request is allowed. If a uid was set to non -1, only layers from the specified uid will be captured. If uid in args is -1, everything will be in the screenshot, so no layers will be skipped 2. If the request doesn't have the permissions, the calling uid is compared to the uid in the request. If they match, we allow the screenshot code to proceed and only screenshot the layers with the matching uid. 3. Otherwise, we return with PERMISSION_DENIED Test: ScreenCaptureTest Bug: 155825630 Change-Id: I129b5a7f489383bf6d2f0ee333a416babc1444a2 --- libs/gui/LayerState.cpp | 6 +- libs/gui/include/gui/LayerState.h | 2 + services/surfaceflinger/Layer.h | 4 +- services/surfaceflinger/RegionSamplingThread.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 57 ++++++-- services/surfaceflinger/SurfaceFlinger.h | 4 +- .../surfaceflinger/tests/LayerTransaction_test.cpp | 35 ----- .../surfaceflinger/tests/ScreenCapture_test.cpp | 158 +++++++++++++++++++++ .../tests/unittests/CompositionTest.cpp | 3 +- .../tests/unittests/TestableSurfaceFlinger.h | 4 +- .../surfaceflinger/tests/utils/ScreenshotUtils.h | 14 +- 11 files changed, 227 insertions(+), 62 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index b215756d56..d07d4352ec 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -509,7 +509,8 @@ status_t CaptureArgs::write(Parcel& output) const { status_t status = output.writeInt32(static_cast(pixelFormat)) ?: output.write(sourceCrop) ?: output.writeFloat(frameScale) ?: - output.writeBool(captureSecureLayers); + output.writeBool(captureSecureLayers) ?: + output.writeInt32(uid); return status; } @@ -518,7 +519,8 @@ status_t CaptureArgs::read(const Parcel& input) { status_t status = input.readInt32(&format) ?: input.read(sourceCrop) ?: input.readFloat(&frameScale) ?: - input.readBool(&captureSecureLayers); + input.readBool(&captureSecureLayers) ?: + input.readInt32(&uid); pixelFormat = static_cast(format); return status; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 5e1066ba68..387ddea2bf 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -314,12 +314,14 @@ static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName); struct CaptureArgs { + const static int32_t UNSET_UID = -1; virtual ~CaptureArgs() = default; ui::PixelFormat pixelFormat{ui::PixelFormat::RGBA_8888}; Rect sourceCrop; float frameScale{1}; bool captureSecureLayers{false}; + int32_t uid{UNSET_UID}; virtual status_t write(Parcel& output) const; virtual status_t read(const Parcel& input); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 5fbdc3424d..8d8ab6dbae 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -436,9 +436,7 @@ public: // Deprecated, please use compositionengine::Output::belongsInOutput() // instead. // TODO(lpique): Move the remaining callers (screencap) to the new function. - bool belongsToDisplay(uint32_t layerStack, bool isPrimaryDisplay) const { - return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay); - } + bool belongsToDisplay(uint32_t layerStack) const { return getLayerStack() == layerStack; } FloatRect getBounds(const Region& activeTransparentRegion) const; FloatRect getBounds() const; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 17daadba02..4e841e9be6 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -429,7 +429,7 @@ void RegionSamplingThread::captureSample() { bounds.top, bounds.right, bounds.bottom); visitor(layer); }; - mFlinger.traverseLayersInLayerStack(layerStack, filterVisitor); + mFlinger.traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, filterVisitor); }; sp buffer = nullptr; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9d9a4cfdb0..6fae56aedb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4958,11 +4958,13 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { // special permissions. case SET_FRAME_RATE: case GET_DISPLAY_BRIGHTNESS_SUPPORT: + // captureLayers and captureDisplay will handle the permission check in the function + case CAPTURE_LAYERS: + case CAPTURE_DISPLAY: case SET_DISPLAY_BRIGHTNESS: { return OK; } - case CAPTURE_LAYERS: - case CAPTURE_DISPLAY: + case ADD_REGION_SAMPLING_LISTENER: case REMOVE_REGION_SAMPLING_LISTENER: { // codes that require permission check @@ -5434,10 +5436,33 @@ static Dataspace pickDataspaceFromColorMode(const ColorMode colorMode) { } } +static status_t validateScreenshotPermissions(const CaptureArgs& captureArgs) { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if (uid == AID_GRAPHICS || PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { + return OK; + } + + // If the caller doesn't have the correct permissions but is only attempting to screenshot + // itself, we allow it to continue. + if (captureArgs.uid == uid) { + return OK; + } + + ALOGE("Permission Denial: can't take screenshot pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; +} + status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, ScreenCaptureResults& captureResults) { ATRACE_CALL(); + status_t validate = validateScreenshotPermissions(args); + if (validate != OK) { + return validate; + } + if (!args.displayToken) return BAD_VALUE; auto renderAreaRotation = ui::Transform::toRotationFlags(args.rotation); @@ -5472,8 +5497,8 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, renderAreaRotation, args.captureSecureLayers); }); - auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) { - traverseLayersInLayerStack(layerStack, visitor); + auto traverseLayers = [this, args, layerStack](const LayerVector::Visitor& visitor) { + traverseLayersInLayerStack(layerStack, args.uid, visitor); }; return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, args.pixelFormat, args.useIdentityTransform, captureResults); @@ -5567,7 +5592,7 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, }); auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) { - traverseLayersInLayerStack(layerStack, visitor); + traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor); }; return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, @@ -5579,6 +5604,11 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, ScreenCaptureResults& captureResults) { ATRACE_CALL(); + status_t validate = validateScreenshotPermissions(args); + if (validate != OK) { + return validate; + } + ui::Size reqSize; sp parent; Rect crop(args.sourceCrop); @@ -5652,19 +5682,19 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, } bool childrenOnly = args.childrenOnly; - RenderAreaFuture renderAreaFuture = promise::defer([=]() -> std::unique_ptr { return std::make_unique(*this, parent, crop, reqSize, dataspace, childrenOnly, displayViewport, captureSecureLayers); }); - auto traverseLayers = [parent, childrenOnly, - &excludeLayers](const LayerVector::Visitor& visitor) { + auto traverseLayers = [parent, args, &excludeLayers](const LayerVector::Visitor& visitor) { parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { if (!layer->isVisible()) { return; - } else if (childrenOnly && layer == parent.get()) { + } else if (args.childrenOnly && layer == parent.get()) { + return; + } else if (args.uid != CaptureArgs::UNSET_UID && args.uid != layer->getOwnerUid()) { return; } @@ -5890,22 +5920,25 @@ void SurfaceFlinger::State::traverseInReverseZOrder(const LayerVector::Visitor& layersSortedByZ.traverseInReverseZOrder(stateSet, visitor); } -void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack, +void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack, const int32_t uid, const LayerVector::Visitor& visitor) { // We loop through the first level of layers without traversing, // as we need to determine which layers belong to the requested display. for (const auto& layer : mDrawingState.layersSortedByZ) { - if (!layer->belongsToDisplay(layerStack, false)) { + if (!layer->belongsToDisplay(layerStack)) { continue; } // relative layers are traversed in Layer::traverseInZOrder layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - if (!layer->belongsToDisplay(layerStack, false)) { + if (layer->getPrimaryDisplayOnly()) { return; } if (!layer->isVisible()) { return; } + if (uid != CaptureArgs::UNSET_UID && layer->getOwnerUid() != uid) { + return; + } visitor(layer); }); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6c00931941..a1b9b14647 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -731,7 +731,9 @@ private: sp getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); sp getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock); - void traverseLayersInLayerStack(ui::LayerStack, const LayerVector::Visitor&); + // If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a + // matching ownerUid + void traverseLayersInLayerStack(ui::LayerStack, const int32_t uid, const LayerVector::Visitor&); sp mStartPropertySetThread; diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp index 0ef4150bfe..8d715e1597 100644 --- a/services/surfaceflinger/tests/LayerTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp @@ -18,7 +18,6 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" -#include #include #include "LayerTransactionTest.h" @@ -26,40 +25,6 @@ namespace android { using android::hardware::graphics::common::V1_1::BufferUsage; -TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - sp composer = ComposerService::getComposerService(); - Transaction() - .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure) - .apply(true); - ASSERT_EQ(PERMISSION_DENIED, composer->captureDisplay(mCaptureArgs, mCaptureResults)); - - UIDFaker f(AID_SYSTEM); - - // By default the system can capture screenshots with secure layers but they - // will be blacked out - ASSERT_EQ(NO_ERROR, composer->captureDisplay(mCaptureArgs, mCaptureResults)); - - { - SCOPED_TRACE("as system"); - auto shot = screenshot(); - shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK); - } - - // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able - // to receive them...we are expected to take care with the results. - DisplayCaptureArgs args; - args.displayToken = mDisplay; - args.captureSecureLayers = true; - ASSERT_EQ(NO_ERROR, composer->captureDisplay(args, mCaptureResults)); - ASSERT_EQ(true, mCaptureResults.capturedSecureLayers); - ScreenCapture sc(mCaptureResults.buffer); - sc.expectColor(Rect(0, 0, 32, 32), Color::RED); -} - TEST_F(LayerTransactionTest, SetTransformToDisplayInverse_BufferState) { sp layer; ASSERT_NO_FATAL_FAILURE( diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index 149e4d7f78..690f758c15 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -74,6 +74,42 @@ protected: std::unique_ptr mCapture; }; +TEST_F(ScreenCaptureTest, SetFlagsSecureEUidSystem) { + sp layer; + ASSERT_NO_FATAL_FAILURE( + layer = createLayer("test", 32, 32, + ISurfaceComposerClient::eSecure | + ISurfaceComposerClient::eFXSurfaceBufferQueue)); + ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); + + Transaction().show(layer).setLayer(layer, INT32_MAX).apply(true); + + sp composer = ComposerService::getComposerService(); + ASSERT_EQ(PERMISSION_DENIED, composer->captureDisplay(mCaptureArgs, mCaptureResults)); + + UIDFaker f(AID_SYSTEM); + + // By default the system can capture screenshots with secure layers but they + // will be blacked out + ASSERT_EQ(NO_ERROR, composer->captureDisplay(mCaptureArgs, mCaptureResults)); + + { + SCOPED_TRACE("as system"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK); + } + + // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able + // to receive them...we are expected to take care with the results. + DisplayCaptureArgs args; + args.displayToken = mDisplay; + args.captureSecureLayers = true; + ASSERT_EQ(NO_ERROR, composer->captureDisplay(args, mCaptureResults)); + ASSERT_TRUE(mCaptureResults.capturedSecureLayers); + ScreenCapture sc(mCaptureResults.buffer); + sc.expectColor(Rect(0, 0, 32, 32), Color::RED); +} + TEST_F(ScreenCaptureTest, CaptureSingleLayer) { LayerCaptureArgs captureArgs; captureArgs.layerHandle = mBGSurfaceControl->getHandle(); @@ -494,6 +530,128 @@ TEST_F(ScreenCaptureTest, CaputureSecureLayer) { mCapture->expectColor(Rect(30, 30, 60, 60), Color::RED); } +TEST_F(ScreenCaptureTest, CaptureDisplayWithUid) { + uid_t fakeUid = 12345; + + DisplayCaptureArgs captureArgs; + captureArgs.displayToken = mDisplay; + + sp layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32, + ISurfaceComposerClient::eFXSurfaceBufferQueue, + mBGSurfaceControl.get())); + ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); + + Transaction().show(layer).setLayer(layer, INT32_MAX).apply(); + + // Make sure red layer with the background layer is screenshot. + ScreenCapture::captureDisplay(&mCapture, captureArgs); + mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED); + mCapture->expectBorder(Rect(0, 0, 32, 32), {63, 63, 195, 255}); + + // From non system uid, can't request screenshot without a specified uid. + UIDFaker f(fakeUid); + sp composer = ComposerService::getComposerService(); + ASSERT_EQ(PERMISSION_DENIED, composer->captureDisplay(captureArgs, mCaptureResults)); + + // Make screenshot request with current uid set. No layers were created with the current + // uid so screenshot will be black. + captureArgs.uid = fakeUid; + ScreenCapture::captureDisplay(&mCapture, captureArgs); + mCapture->expectColor(Rect(0, 0, 32, 32), Color::BLACK); + mCapture->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + + sp layerWithFakeUid; + // Create a new layer with the current uid + ASSERT_NO_FATAL_FAILURE(layerWithFakeUid = + createLayer("new test layer", 32, 32, + ISurfaceComposerClient::eFXSurfaceBufferQueue, + mBGSurfaceControl.get())); + ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerWithFakeUid, Color::GREEN, 32, 32)); + Transaction() + .show(layerWithFakeUid) + .setLayer(layerWithFakeUid, INT32_MAX) + .setPosition(layerWithFakeUid, 128, 128) + .apply(); + + // Screenshot from the fakeUid caller with the uid requested allows the layer + // with that uid to be screenshotted. Everything else is black + ScreenCapture::captureDisplay(&mCapture, captureArgs); + mCapture->expectColor(Rect(128, 128, 160, 160), Color::GREEN); + mCapture->expectBorder(Rect(128, 128, 160, 160), Color::BLACK); +} + +TEST_F(ScreenCaptureTest, CaptureLayerWithUid) { + uid_t fakeUid = 12345; + + sp layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32, + ISurfaceComposerClient::eFXSurfaceBufferQueue, + mBGSurfaceControl.get())); + ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); + + Transaction().show(layer).setLayer(layer, INT32_MAX).apply(); + + LayerCaptureArgs captureArgs; + captureArgs.layerHandle = mBGSurfaceControl->getHandle(); + captureArgs.childrenOnly = false; + + // Make sure red layer with the background layer is screenshot. + ScreenCapture::captureLayers(&mCapture, captureArgs); + mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED); + mCapture->expectBorder(Rect(0, 0, 32, 32), {63, 63, 195, 255}); + + // From non system uid, can't request screenshot without a specified uid. + std::unique_ptr uidFaker = std::make_unique(fakeUid); + + sp composer = ComposerService::getComposerService(); + ASSERT_EQ(PERMISSION_DENIED, composer->captureLayers(captureArgs, mCaptureResults)); + + // Make screenshot request with current uid set. No layers were created with the current + // uid so screenshot will be black. + captureArgs.uid = fakeUid; + ScreenCapture::captureLayers(&mCapture, captureArgs); + mCapture->expectColor(Rect(0, 0, 32, 32), Color::TRANSPARENT); + mCapture->expectBorder(Rect(0, 0, 32, 32), Color::TRANSPARENT); + + sp layerWithFakeUid; + // Create a new layer with the current uid + ASSERT_NO_FATAL_FAILURE(layerWithFakeUid = + createLayer("new test layer", 32, 32, + ISurfaceComposerClient::eFXSurfaceBufferQueue, + mBGSurfaceControl.get())); + ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerWithFakeUid, Color::GREEN, 32, 32)); + Transaction() + .show(layerWithFakeUid) + .setLayer(layerWithFakeUid, INT32_MAX) + .setPosition(layerWithFakeUid, 128, 128) + // reparent a layer that was created with a different uid to the new layer. + .reparent(layer, layerWithFakeUid->getHandle()) + .apply(); + + // Screenshot from the fakeUid caller with the uid requested allows the layer + // with that uid to be screenshotted. The child layer is skipped since it was created + // from a different uid. + ScreenCapture::captureLayers(&mCapture, captureArgs); + mCapture->expectColor(Rect(128, 128, 160, 160), Color::GREEN); + mCapture->expectBorder(Rect(128, 128, 160, 160), Color::TRANSPARENT); + + // Clear fake calling uid so it's back to system. + uidFaker = nullptr; + // Screenshot from the test caller with the uid requested allows the layer + // with that uid to be screenshotted. The child layer is skipped since it was created + // from a different uid. + ScreenCapture::captureLayers(&mCapture, captureArgs); + mCapture->expectColor(Rect(128, 128, 160, 160), Color::GREEN); + mCapture->expectBorder(Rect(128, 128, 160, 160), Color::TRANSPARENT); + + // Screenshot from the fakeUid caller with no uid requested allows everything to be screenshot. + captureArgs.uid = -1; + ScreenCapture::captureLayers(&mCapture, captureArgs); + mCapture->expectColor(Rect(128, 128, 160, 160), Color::RED); + mCapture->expectBorder(Rect(128, 128, 160, 160), {63, 63, 195, 255}); +} + // In the following tests we verify successful skipping of a parent layer, // so we use the same verification logic and only change how we mutate // the parent layer to verify that various properties are ignored. diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 48c4e18c62..dc8b31e821 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -241,7 +241,8 @@ void CompositionTest::captureScreenComposition() { ui::Dataspace::V0_SRGB, ui::Transform::ROT_0); auto traverseLayers = [this](const LayerVector::Visitor& visitor) { - return mFlinger.traverseLayersInLayerStack(mDisplay->getLayerStack(), visitor); + return mFlinger.traverseLayersInLayerStack(mDisplay->getLayerStack(), + CaptureArgs::UNSET_UID, visitor); }; // TODO: Eliminate expensive/real allocation if possible. diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 3941d4218f..8972907b83 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -343,9 +343,9 @@ public: regionSampling, captureResults); } - auto traverseLayersInLayerStack(ui::LayerStack layerStack, + auto traverseLayersInLayerStack(ui::LayerStack layerStack, int32_t uid, const LayerVector::Visitor& visitor) { - return mFlinger->SurfaceFlinger::traverseLayersInLayerStack(layerStack, visitor); + return mFlinger->SurfaceFlinger::traverseLayersInLayerStack(layerStack, uid, visitor); } auto getDisplayNativePrimaries(const sp& displayToken, diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h index 56628f88bc..081d18b6b8 100644 --- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -31,18 +31,22 @@ public: captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken()); } - static void captureScreen(std::unique_ptr* sc, sp displayToken) { + static void captureDisplay(std::unique_ptr* sc, + const DisplayCaptureArgs& captureArgs) { const auto sf = ComposerService::getComposerService(); SurfaceComposerClient::Transaction().apply(true); - DisplayCaptureArgs args; - args.displayToken = displayToken; - ScreenCaptureResults captureResults; - ASSERT_EQ(NO_ERROR, sf->captureDisplay(args, captureResults)); + ASSERT_EQ(NO_ERROR, sf->captureDisplay(captureArgs, captureResults)); *sc = std::make_unique(captureResults.buffer); } + static void captureScreen(std::unique_ptr* sc, sp displayToken) { + DisplayCaptureArgs args; + args.displayToken = displayToken; + captureDisplay(sc, args); + } + static void captureLayers(std::unique_ptr* sc, const LayerCaptureArgs& captureArgs) { sp sf(ComposerService::getComposerService()); -- cgit v1.2.3-59-g8ed1b From 9c53ee710ecfe4657d08ce58f1609dfb0350237d Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 22 Jul 2020 21:16:18 -0700 Subject: SurfaceFlinger: use duration instead of offset This change is using the duration given to sf/app without converting them back to the legacy offset. This allows us to get the expected vsync associated with a wakeup event. This change also required some refactoring: - Move the periodic callback interface out of DispSync and in to DispSyncSource - Translate legacy offsets to duration in case that duration is not specified in the build files - Add support to VSD to expose the deadline timestamp of when a frame needs to be ready by Bug: 162888874 Test: SF unit tests Test: examine systraces Change-Id: I87a53cc7dea931d3c195eab6842e003ca4516885 --- services/surfaceflinger/RegionSamplingThread.cpp | 52 +-- services/surfaceflinger/RegionSamplingThread.h | 8 +- services/surfaceflinger/Scheduler/DispSync.h | 17 - .../surfaceflinger/Scheduler/DispSyncSource.cpp | 161 +++++--- services/surfaceflinger/Scheduler/DispSyncSource.h | 26 +- services/surfaceflinger/Scheduler/EventThread.cpp | 8 +- services/surfaceflinger/Scheduler/EventThread.h | 15 +- .../surfaceflinger/Scheduler/InjectVSyncSource.h | 7 +- services/surfaceflinger/Scheduler/Scheduler.cpp | 24 +- services/surfaceflinger/Scheduler/Scheduler.h | 20 +- services/surfaceflinger/Scheduler/VSyncDispatch.h | 61 ++- .../Scheduler/VSyncDispatchTimerQueue.cpp | 80 ++-- .../Scheduler/VSyncDispatchTimerQueue.h | 20 +- .../surfaceflinger/Scheduler/VSyncPredictor.cpp | 32 +- services/surfaceflinger/Scheduler/VSyncPredictor.h | 4 +- services/surfaceflinger/Scheduler/VSyncReactor.cpp | 165 +------- services/surfaceflinger/Scheduler/VSyncReactor.h | 11 - services/surfaceflinger/SurfaceFlinger.cpp | 30 +- services/surfaceflinger/TracedOrdinal.h | 26 +- .../tests/unittests/DispSyncSourceTest.cpp | 215 +++++++++-- .../tests/unittests/DisplayTransactionTest.cpp | 9 - .../tests/unittests/EventThreadTest.cpp | 60 +-- .../tests/unittests/SchedulerTest.cpp | 8 +- .../tests/unittests/VSyncDispatchRealtimeTest.cpp | 27 +- .../unittests/VSyncDispatchTimerQueueTest.cpp | 416 +++++++++++++++------ .../tests/unittests/VSyncReactorTest.cpp | 246 +----------- .../tests/unittests/mock/MockDispSync.cpp | 35 -- .../tests/unittests/mock/MockDispSync.h | 18 - .../tests/unittests/mock/MockEventThread.h | 4 +- 29 files changed, 928 insertions(+), 877 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 0157a7f576..b24855d77c 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -61,7 +61,7 @@ enum class samplingStep { constexpr auto timeForRegionSampling = 5000000ns; constexpr auto maxRegionSamplingSkips = 10; -constexpr auto defaultRegionSamplingOffset = -3ms; +constexpr auto defaultRegionSamplingWorkDuration = 3ms; constexpr auto defaultRegionSamplingPeriod = 100ms; constexpr auto defaultRegionSamplingTimerTimeout = 100ms; // TODO: (b/127403193) duration to string conversion could probably be constexpr @@ -73,9 +73,9 @@ inline std::string toNsString(std::chrono::duration t) { RegionSamplingThread::EnvironmentTimingTunables::EnvironmentTimingTunables() { char value[PROPERTY_VALUE_MAX] = {}; - property_get("debug.sf.region_sampling_offset_ns", value, - toNsString(defaultRegionSamplingOffset).c_str()); - int const samplingOffsetNsRaw = atoi(value); + property_get("debug.sf.region_sampling_duration_ns", value, + toNsString(defaultRegionSamplingWorkDuration).c_str()); + int const samplingDurationNsRaw = atoi(value); property_get("debug.sf.region_sampling_period_ns", value, toNsString(defaultRegionSamplingPeriod).c_str()); @@ -87,22 +87,26 @@ RegionSamplingThread::EnvironmentTimingTunables::EnvironmentTimingTunables() { if ((samplingPeriodNsRaw < 0) || (samplingTimerTimeoutNsRaw < 0)) { ALOGW("User-specified sampling tuning options nonsensical. Using defaults"); - mSamplingOffset = defaultRegionSamplingOffset; + mSamplingDuration = defaultRegionSamplingWorkDuration; mSamplingPeriod = defaultRegionSamplingPeriod; mSamplingTimerTimeout = defaultRegionSamplingTimerTimeout; } else { - mSamplingOffset = std::chrono::nanoseconds(samplingOffsetNsRaw); + mSamplingDuration = std::chrono::nanoseconds(samplingDurationNsRaw); mSamplingPeriod = std::chrono::nanoseconds(samplingPeriodNsRaw); mSamplingTimerTimeout = std::chrono::nanoseconds(samplingTimerTimeoutNsRaw); } } -struct SamplingOffsetCallback : DispSync::Callback { +struct SamplingOffsetCallback : VSyncSource::Callback { SamplingOffsetCallback(RegionSamplingThread& samplingThread, Scheduler& scheduler, - std::chrono::nanoseconds targetSamplingOffset) + std::chrono::nanoseconds targetSamplingWorkDuration) : mRegionSamplingThread(samplingThread), - mScheduler(scheduler), - mTargetSamplingOffset(targetSamplingOffset) {} + mTargetSamplingWorkDuration(targetSamplingWorkDuration), + mVSyncSource(scheduler.makePrimaryDispSyncSource("SamplingThreadDispSyncListener", 0ns, + 0ns, + /*traceVsync=*/false)) { + mVSyncSource->setCallback(this); + } ~SamplingOffsetCallback() { stopVsyncListener(); } @@ -114,8 +118,7 @@ struct SamplingOffsetCallback : DispSync::Callback { if (mVsyncListening) return; mPhaseIntervalSetting = Phase::ZERO; - mScheduler.getPrimaryDispSync().addEventListener("SamplingThreadDispSyncListener", 0, this, - mLastCallbackTime); + mVSyncSource->setVSyncEnabled(true); mVsyncListening = true; } @@ -128,23 +131,24 @@ private: void stopVsyncListenerLocked() /*REQUIRES(mMutex)*/ { if (!mVsyncListening) return; - mScheduler.getPrimaryDispSync().removeEventListener(this, &mLastCallbackTime); + mVSyncSource->setVSyncEnabled(false); mVsyncListening = false; } - void onDispSyncEvent(nsecs_t /*when*/, nsecs_t /*expectedVSyncTimestamp*/) final { + void onVSyncEvent(nsecs_t /*when*/, nsecs_t /*expectedVSyncTimestamp*/, + nsecs_t /*deadlineTimestamp*/) final { std::unique_lock lock(mMutex); if (mPhaseIntervalSetting == Phase::ZERO) { ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::waitForSamplePhase)); mPhaseIntervalSetting = Phase::SAMPLING; - mScheduler.getPrimaryDispSync().changePhaseOffset(this, mTargetSamplingOffset.count()); + mVSyncSource->setDuration(mTargetSamplingWorkDuration, 0ns); return; } if (mPhaseIntervalSetting == Phase::SAMPLING) { mPhaseIntervalSetting = Phase::ZERO; - mScheduler.getPrimaryDispSync().changePhaseOffset(this, 0); + mVSyncSource->setDuration(0ns, 0ns); stopVsyncListenerLocked(); lock.unlock(); mRegionSamplingThread.notifySamplingOffset(); @@ -153,16 +157,15 @@ private: } RegionSamplingThread& mRegionSamplingThread; - Scheduler& mScheduler; - const std::chrono::nanoseconds mTargetSamplingOffset; + const std::chrono::nanoseconds mTargetSamplingWorkDuration; mutable std::mutex mMutex; - nsecs_t mLastCallbackTime = 0; enum class Phase { ZERO, SAMPLING } mPhaseIntervalSetting /*GUARDED_BY(mMutex) macro doesnt work with unique_lock?*/ = Phase::ZERO; bool mVsyncListening /*GUARDED_BY(mMutex)*/ = false; + std::unique_ptr mVSyncSource; }; RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler, @@ -170,11 +173,12 @@ RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& s : mFlinger(flinger), mScheduler(scheduler), mTunables(tunables), - mIdleTimer(std::chrono::duration_cast( - mTunables.mSamplingTimerTimeout), - [] {}, [this] { checkForStaleLuma(); }), + mIdleTimer( + std::chrono::duration_cast( + mTunables.mSamplingTimerTimeout), + [] {}, [this] { checkForStaleLuma(); }), mPhaseCallback(std::make_unique(*this, mScheduler, - tunables.mSamplingOffset)), + tunables.mSamplingDuration)), lastSampleTime(0ns) { mThread = std::thread([this]() { threadMain(); }); pthread_setname_np(mThread.native_handle(), "RegionSamplingThread"); @@ -183,7 +187,7 @@ RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& s RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler) : RegionSamplingThread(flinger, scheduler, - TimingTunables{defaultRegionSamplingOffset, + TimingTunables{defaultRegionSamplingWorkDuration, defaultRegionSamplingPeriod, defaultRegionSamplingTimerTimeout}) {} diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h index b9b7a3c436..0defdb3fcb 100644 --- a/services/surfaceflinger/RegionSamplingThread.h +++ b/services/surfaceflinger/RegionSamplingThread.h @@ -43,10 +43,10 @@ float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t st class RegionSamplingThread : public IBinder::DeathRecipient { public: struct TimingTunables { - // debug.sf.sampling_offset_ns - // When asynchronously collecting sample, the offset, from zero phase in the vsync timeline - // at which the sampling should start. - std::chrono::nanoseconds mSamplingOffset; + // debug.sf.sampling_duration_ns + // When asynchronously collecting sample, the duration, at which the sampling should start + // before a vsync + std::chrono::nanoseconds mSamplingDuration; // debug.sf.sampling_period_ns // This is the maximum amount of time the luma recieving client // should have to wait for a new luma value after a frame is updated. The inverse of this is diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h index 7b2c9c349e..f34aabce19 100644 --- a/services/surfaceflinger/Scheduler/DispSync.h +++ b/services/surfaceflinger/Scheduler/DispSync.h @@ -32,32 +32,15 @@ class FenceTime; class DispSync { public: - class Callback { - public: - Callback() = default; - virtual ~Callback() = default; - virtual void onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) = 0; - - protected: - Callback(Callback const&) = delete; - Callback& operator=(Callback const&) = delete; - }; - DispSync() = default; virtual ~DispSync() = default; - virtual void reset() = 0; virtual bool addPresentFence(const std::shared_ptr&) = 0; virtual void beginResync() = 0; virtual bool addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, bool* periodFlushed) = 0; - virtual void endResync() = 0; virtual void setPeriod(nsecs_t period) = 0; virtual nsecs_t getPeriod() = 0; - virtual status_t addEventListener(const char* name, nsecs_t phase, Callback* callback, - nsecs_t lastCallbackTime) = 0; - virtual status_t removeEventListener(Callback* callback, nsecs_t* outLastCallback) = 0; - virtual status_t changePhaseOffset(Callback* callback, nsecs_t phase) = 0; virtual nsecs_t computeNextRefresh(int periodOffset, nsecs_t now) const = 0; virtual void setIgnorePresentFences(bool ignore) = 0; virtual nsecs_t expectedPresentTime(nsecs_t now) = 0; diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 8752b6600e..75f072dcd4 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "DispSyncSource.h" @@ -29,34 +25,129 @@ #include "DispSync.h" #include "EventThread.h" -namespace android { +namespace android::scheduler { using base::StringAppendF; +using namespace std::chrono_literals; + +// The DispSync interface has a 'repeat this callback at rate' semantic. This object adapts +// VSyncDispatch's individually-scheduled callbacks so as to meet DispSync's existing semantic +// for now. +class CallbackRepeater { +public: + CallbackRepeater(VSyncDispatch& dispatch, VSyncDispatch::Callback cb, const char* name, + std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, + std::chrono::nanoseconds notBefore) + : mName(name), + mCallback(cb), + mRegistration(dispatch, + std::bind(&CallbackRepeater::callback, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3), + mName), + mStarted(false), + mWorkDuration(workDuration), + mReadyDuration(readyDuration), + mLastCallTime(notBefore) {} + + ~CallbackRepeater() { + std::lock_guard lock(mMutex); + mRegistration.cancel(); + } + + void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) { + std::lock_guard lock(mMutex); + mStarted = true; + mWorkDuration = workDuration; + mReadyDuration = readyDuration; + + auto const scheduleResult = + mRegistration.schedule({.workDuration = mWorkDuration.count(), + .readyDuration = mReadyDuration.count(), + .earliestVsync = mLastCallTime.count()}); + LOG_ALWAYS_FATAL_IF((scheduleResult != scheduler::ScheduleResult::Scheduled), + "Error scheduling callback: rc %X", scheduleResult); + } + + void stop() { + std::lock_guard lock(mMutex); + LOG_ALWAYS_FATAL_IF(!mStarted, "DispSyncInterface misuse: callback already stopped"); + mStarted = false; + mRegistration.cancel(); + } + + void dump(std::string& result) const { + std::lock_guard lock(mMutex); + const auto relativeLastCallTime = + mLastCallTime - std::chrono::steady_clock::now().time_since_epoch(); + StringAppendF(&result, "\t%s: ", mName.c_str()); + StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ", + mWorkDuration.count() / 1e6f, mReadyDuration.count() / 1e6f); + StringAppendF(&result, "%.2fms relative to now (%s)\n", relativeLastCallTime.count() / 1e6f, + mStarted ? "running" : "stopped"); + } + +private: + void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) { + { + std::lock_guard lock(mMutex); + mLastCallTime = std::chrono::nanoseconds(vsyncTime); + } + + mCallback(vsyncTime, wakeupTime, readyTime); + + { + std::lock_guard lock(mMutex); + if (!mStarted) { + return; + } + auto const scheduleResult = + mRegistration.schedule({.workDuration = mWorkDuration.count(), + .readyDuration = mReadyDuration.count(), + .earliestVsync = vsyncTime}); + LOG_ALWAYS_FATAL_IF((scheduleResult != ScheduleResult::Scheduled), + "Error rescheduling callback: rc %X", scheduleResult); + } + } -DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, + const std::string mName; + scheduler::VSyncDispatch::Callback mCallback; + + mutable std::mutex mMutex; + VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex); + bool mStarted GUARDED_BY(mMutex) = false; + std::chrono::nanoseconds mWorkDuration GUARDED_BY(mMutex) = 0ns; + std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex) = 0ns; + std::chrono::nanoseconds mLastCallTime GUARDED_BY(mMutex) = 0ns; +}; + +DispSyncSource::DispSyncSource(scheduler::VSyncDispatch& vSyncDispatch, + std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration, bool traceVsync, const char* name) : mName(name), mValue(base::StringPrintf("VSYNC-%s", name), 0), mTraceVsync(traceVsync), mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)), - mDispSync(dispSync), - mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset) {} + mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration), + mReadyDuration(readyDuration) { + mCallbackRepeater = + std::make_unique(vSyncDispatch, + std::bind(&DispSyncSource::onVsyncCallback, this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + name, workDuration, readyDuration, + std::chrono::steady_clock::now().time_since_epoch()); +} + +DispSyncSource::~DispSyncSource() = default; void DispSyncSource::setVSyncEnabled(bool enable) { std::lock_guard lock(mVsyncMutex); if (enable) { - status_t err = mDispSync->addEventListener(mName, mPhaseOffset, - static_cast(this), - mLastCallbackTime); - if (err != NO_ERROR) { - ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err); - } + mCallbackRepeater->start(mWorkDuration, mReadyDuration); // ATRACE_INT(mVsyncOnLabel.c_str(), 1); } else { - status_t err = mDispSync->removeEventListener(static_cast(this), - &mLastCallbackTime); - if (err != NO_ERROR) { - ALOGE("error unregistering vsync callback: %s (%d)", strerror(-err), err); - } + mCallbackRepeater->stop(); // ATRACE_INT(mVsyncOnLabel.c_str(), 0); } mEnabled = enable; @@ -67,32 +158,22 @@ void DispSyncSource::setCallback(VSyncSource::Callback* callback) { mCallback = callback; } -void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) { +void DispSyncSource::setDuration(std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration) { std::lock_guard lock(mVsyncMutex); - const nsecs_t period = mDispSync->getPeriod(); - - // Normalize phaseOffset to [-period, period) - const int numPeriods = phaseOffset / period; - phaseOffset -= numPeriods * period; - if (mPhaseOffset == phaseOffset) { - return; - } - - mPhaseOffset = phaseOffset; + mWorkDuration = workDuration; + mReadyDuration = readyDuration; // If we're not enabled, we don't need to mess with the listeners if (!mEnabled) { return; } - status_t err = - mDispSync->changePhaseOffset(static_cast(this), mPhaseOffset); - if (err != NO_ERROR) { - ALOGE("error changing vsync offset: %s (%d)", strerror(-err), err); - } + mCallbackRepeater->start(mWorkDuration, mReadyDuration); } -void DispSyncSource::onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) { +void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, + nsecs_t readyTime) { VSyncSource::Callback* callback; { std::lock_guard lock(mCallbackMutex); @@ -104,17 +185,13 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestam } if (callback != nullptr) { - callback->onVSyncEvent(when, expectedVSyncTimestamp); + callback->onVSyncEvent(targetWakeupTime, vsyncTime, readyTime); } } void DispSyncSource::dump(std::string& result) const { std::lock_guard lock(mVsyncMutex); StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled"); - mDispSync->dump(result); } -} // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h index 2aee3f6321..2fce235546 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.h +++ b/services/surfaceflinger/Scheduler/DispSyncSource.h @@ -18,45 +18,47 @@ #include #include -#include "DispSync.h" #include "EventThread.h" #include "TracedOrdinal.h" +#include "VSyncDispatch.h" -namespace android { +namespace android::scheduler { +class CallbackRepeater; -class DispSyncSource final : public VSyncSource, private DispSync::Callback { +class DispSyncSource final : public VSyncSource { public: - DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name); + DispSyncSource(VSyncDispatch& vSyncDispatch, std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration, bool traceVsync, const char* name); - ~DispSyncSource() override = default; + ~DispSyncSource() override; // The following methods are implementation of VSyncSource. const char* getName() const override { return mName; } void setVSyncEnabled(bool enable) override; void setCallback(VSyncSource::Callback* callback) override; - void setPhaseOffset(nsecs_t phaseOffset) override; + void setDuration(std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration) override; void dump(std::string&) const override; private: - // The following method is the implementation of the DispSync::Callback. - void onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override; + void onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime); const char* const mName; TracedOrdinal mValue; const bool mTraceVsync; const std::string mVsyncOnLabel; - nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0; - DispSync* mDispSync; + std::unique_ptr mCallbackRepeater; std::mutex mCallbackMutex; VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr; mutable std::mutex mVsyncMutex; - TracedOrdinal mPhaseOffset GUARDED_BY(mVsyncMutex); + TracedOrdinal mWorkDuration GUARDED_BY(mVsyncMutex); + std::chrono::nanoseconds mReadyDuration GUARDED_BY(mVsyncMutex); bool mEnabled GUARDED_BY(mVsyncMutex) = false; }; -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 846190c7eb..559626b24f 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -200,9 +200,10 @@ EventThread::~EventThread() { mThread.join(); } -void EventThread::setPhaseOffset(nsecs_t phaseOffset) { +void EventThread::setDuration(std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration) { std::lock_guard lock(mMutex); - mVSyncSource->setPhaseOffset(phaseOffset); + mVSyncSource->setDuration(workDuration, readyDuration); } sp EventThread::createEventConnection( @@ -283,7 +284,8 @@ void EventThread::onScreenAcquired() { mCondition.notify_all(); } -void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp) { +void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, + nsecs_t /*deadlineTimestamp*/) { std::lock_guard lock(mMutex); LOG_FATAL_IF(!mVSyncState); diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 49f624c35e..fa1ca64c86 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -57,7 +57,8 @@ public: class Callback { public: virtual ~Callback() {} - virtual void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) = 0; + virtual void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) = 0; }; virtual ~VSyncSource() {} @@ -65,7 +66,8 @@ public: virtual const char* getName() const = 0; virtual void setVSyncEnabled(bool enable) = 0; virtual void setCallback(Callback* callback) = 0; - virtual void setPhaseOffset(nsecs_t phaseOffset) = 0; + virtual void setDuration(std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration) = 0; virtual void dump(std::string& result) const = 0; }; @@ -116,7 +118,8 @@ public: virtual void dump(std::string& result) const = 0; - virtual void setPhaseOffset(nsecs_t phaseOffset) = 0; + virtual void setDuration(std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration) = 0; virtual status_t registerDisplayEventConnection( const sp& connection) = 0; @@ -157,7 +160,8 @@ public: void dump(std::string& result) const override; - void setPhaseOffset(nsecs_t phaseOffset) override; + void setDuration(std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration) override; size_t getEventThreadConnectionCount() override; @@ -177,7 +181,8 @@ private: REQUIRES(mMutex); // Implements VSyncSource::Callback - void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp) override; + void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) override; const std::unique_ptr mVSyncSource GUARDED_BY(mMutex); diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h index 975c9db41a..016b076444 100644 --- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h +++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h @@ -35,16 +35,17 @@ public: mCallback = callback; } - void onInjectSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) { + void onInjectSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) { std::lock_guard lock(mCallbackMutex); if (mCallback) { - mCallback->onVSyncEvent(when, expectedVSyncTimestamp); + mCallback->onVSyncEvent(when, expectedVSyncTimestamp, deadlineTimestamp); } } const char* getName() const override { return "inject"; } void setVSyncEnabled(bool) override {} - void setPhaseOffset(nsecs_t) override {} + void setDuration(std::chrono::nanoseconds, std::chrono::nanoseconds) override {} void dump(std::string&) const override {} private: diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 5f7b2c280d..017872c945 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -184,16 +184,18 @@ DispSync& Scheduler::getPrimaryDispSync() { return *mVsyncSchedule.sync; } -std::unique_ptr Scheduler::makePrimaryDispSyncSource(const char* name, - nsecs_t phaseOffsetNs) { - return std::make_unique(&getPrimaryDispSync(), phaseOffsetNs, - true /* traceVsync */, name); +std::unique_ptr Scheduler::makePrimaryDispSyncSource( + const char* name, std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration, bool traceVsync) { + return std::make_unique(*mVsyncSchedule.dispatch, workDuration, + readyDuration, traceVsync, name); } Scheduler::ConnectionHandle Scheduler::createConnection( - const char* connectionName, nsecs_t phaseOffsetNs, + const char* connectionName, std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration, impl::EventThread::InterceptVSyncsCallback interceptCallback) { - auto vsyncSource = makePrimaryDispSyncSource(connectionName, phaseOffsetNs); + auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration); auto eventThread = std::make_unique(std::move(vsyncSource), std::move(interceptCallback)); return createConnection(std::move(eventThread)); @@ -286,9 +288,10 @@ void Scheduler::dump(ConnectionHandle handle, std::string& result) const { mConnections.at(handle).thread->dump(result); } -void Scheduler::setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) { +void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration) { RETURN_IF_INVALID_HANDLE(handle); - mConnections[handle].thread->setPhaseOffset(phaseOffset); + mConnections[handle].thread->setDuration(workDuration, readyDuration); } void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) { @@ -318,12 +321,12 @@ Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { return mInjectorConnectionHandle; } -bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime) { +bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime, nsecs_t deadlineTimestamp) { if (!mInjectVSyncs || !mVSyncInjector) { return false; } - mVSyncInjector->onInjectSyncEvent(when, expectedVSyncTime); + mVSyncInjector->onInjectSyncEvent(when, expectedVSyncTime, deadlineTimestamp); return true; } @@ -340,7 +343,6 @@ void Scheduler::disableHardwareVsync(bool makeUnavailable) { std::lock_guard lock(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { mSchedulerCallback.setVsyncEnabled(false); - getPrimaryDispSync().endResync(); mPrimaryHWVsyncEnabled = false; } if (makeUnavailable) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index ed68b86311..44d0d77766 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -71,7 +71,9 @@ public: DispSync& getPrimaryDispSync(); using ConnectionHandle = scheduler::ConnectionHandle; - ConnectionHandle createConnection(const char* connectionName, nsecs_t phaseOffsetNs, + ConnectionHandle createConnection(const char* connectionName, + std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration, impl::EventThread::InterceptVSyncsCallback); sp createDisplayEventConnection(ConnectionHandle, @@ -88,17 +90,16 @@ public: void onScreenAcquired(ConnectionHandle); void onScreenReleased(ConnectionHandle); - // Modifies phase offset in the event thread. - void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset); + // Modifies work duration in the event thread. + void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration); void getDisplayStatInfo(DisplayStatInfo* stats); // Returns injector handle if injection has toggled, or an invalid handle otherwise. ConnectionHandle enableVSyncInjection(bool enable); - // Returns false if injection is disabled. - bool injectVSync(nsecs_t when, nsecs_t expectedVSyncTime); - + bool injectVSync(nsecs_t when, nsecs_t expectedVSyncTime, nsecs_t deadlineTimestamp); void enableHardwareVsync(); void disableHardwareVsync(bool makeUnavailable); @@ -151,6 +152,11 @@ public: size_t getEventThreadConnectionCount(ConnectionHandle handle); + std::unique_ptr makePrimaryDispSyncSource(const char* name, + std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration, + bool traceVsync = true); + private: friend class TestableScheduler; @@ -186,8 +192,6 @@ private: static std::unique_ptr createLayerHistory(const scheduler::RefreshRateConfigs&, bool useContentDetectionV2); - std::unique_ptr makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs); - // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr); sp createConnectionInternal(EventThread*, diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h index 2a2d7c5279..0407900406 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatch.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h @@ -40,11 +40,13 @@ public: /* * A callback that can be registered to be awoken at a given time relative to a vsync event. - * \param [in] vsyncTime The timestamp of the vsync the callback is for. - * \param [in] targetWakeupTime The timestamp of intended wakeup time of the cb. - * + * \param [in] vsyncTime: The timestamp of the vsync the callback is for. + * \param [in] targetWakeupTime: The timestamp of intended wakeup time of the cb. + * \param [in] readyTime: The timestamp of intended time where client needs to finish + * its work by. */ - using Callback = std::function; + using Callback = + std::function; /* * Registers a callback that will be called at designated points on the vsync timeline. @@ -70,34 +72,55 @@ public: */ virtual void unregisterCallback(CallbackToken token) = 0; + /* + * Timing information about a scheduled callback + * + * @workDuration: The time needed for the client to perform its work + * @readyDuration: The time needed for the client to be ready before a vsync event. + * For external (non-SF) clients, not only do we need to account for their + * workDuration, but we also need to account for the time SF will take to + * process their buffer/transaction. In this case, readyDuration will be set + * to the SF duration in order to provide enough end-to-end time, and to be + * able to provide the ready-by time (deadline) on the callback. + * For internal clients, we don't need to add additional padding, so + * readyDuration will typically be 0. + * @earliestVsync: The targeted display time. This will be snapped to the closest + * predicted vsync time after earliestVsync. + * + * callback will be dispatched at 'workDuration + readyDuration' nanoseconds before a vsync + * event. + */ + struct ScheduleTiming { + nsecs_t workDuration = 0; + nsecs_t readyDuration = 0; + nsecs_t earliestVsync = 0; + }; + /* * Schedules the registered callback to be dispatched. * - * The callback will be dispatched at 'workDuration' nanoseconds before a vsync event. + * The callback will be dispatched at 'workDuration + readyDuration' nanoseconds before a vsync + * event. * * The caller designates the earliest vsync event that should be targeted by the earliestVsync * parameter. - * The callback will be scheduled at (workDuration - predictedVsync), where predictedVsync - * is the first vsync event time where ( predictedVsync >= earliestVsync ). + * The callback will be scheduled at (workDuration + readyDuration - predictedVsync), where + * predictedVsync is the first vsync event time where ( predictedVsync >= earliestVsync ). * - * If (workDuration - earliestVsync) is in the past, or if a callback has already been - * dispatched for the predictedVsync, an error will be returned. + * If (workDuration + readyDuration - earliestVsync) is in the past, or if a callback has + * already been dispatched for the predictedVsync, an error will be returned. * * It is valid to reschedule a callback to a different time. * * \param [in] token The callback to schedule. - * \param [in] workDuration The time before the actual vsync time to invoke the callback - * associated with token. - * \param [in] earliestVsync The targeted display time. This will be snapped to the closest - * predicted vsync time after earliestVsync. + * \param [in] scheduleTiming The timing information for this schedule call * \return A ScheduleResult::Scheduled if callback was scheduled. * A ScheduleResult::CannotSchedule - * if (workDuration - earliestVsync) is in the past, or - * if a callback was dispatched for the predictedVsync already. - * A ScheduleResult::Error if there was another error. + * if (workDuration + readyDuration - earliestVsync) is in the past, + * or if a callback was dispatched for the predictedVsync already. A ScheduleResult::Error if + * there was another error. */ - virtual ScheduleResult schedule(CallbackToken token, nsecs_t workDuration, - nsecs_t earliestVsync) = 0; + virtual ScheduleResult schedule(CallbackToken token, ScheduleTiming scheduleTiming) = 0; /* Cancels a scheduled callback, if possible. * @@ -129,7 +152,7 @@ public: ~VSyncCallbackRegistration(); // See documentation for VSyncDispatch::schedule. - ScheduleResult schedule(nsecs_t workDuration, nsecs_t earliestVsync); + ScheduleResult schedule(VSyncDispatch::ScheduleTiming scheduleTiming); // See documentation for VSyncDispatch::cancel. CancelResult cancel(); diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp index ef9268015c..2154a40517 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp @@ -35,8 +35,6 @@ VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string const& na nsecs_t minVsyncDistance) : mName(name), mCallback(cb), - mWorkDuration(0), - mEarliestVsync(0), mMinVsyncDistance(minVsyncDistance) {} std::optional VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const { @@ -54,6 +52,13 @@ std::optional VSyncDispatchTimerQueueEntry::wakeupTime() const { return {mArmedInfo->mActualWakeupTime}; } +std::optional VSyncDispatchTimerQueueEntry::readyTime() const { + if (!mArmedInfo) { + return {}; + } + return {mArmedInfo->mActualReadyTime}; +} + std::optional VSyncDispatchTimerQueueEntry::targetVsync() const { if (!mArmedInfo) { return {}; @@ -61,10 +66,10 @@ std::optional VSyncDispatchTimerQueueEntry::targetVsync() const { return {mArmedInfo->mActualVsyncTime}; } -ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync, +ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing, VSyncTracker& tracker, nsecs_t now) { - auto nextVsyncTime = - tracker.nextAnticipatedVSyncTimeFrom(std::max(earliestVsync, now + workDuration)); + auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom( + std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration)); bool const wouldSkipAVsyncTarget = mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance)); @@ -80,16 +85,15 @@ ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsec tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance); } - auto const nextWakeupTime = nextVsyncTime - workDuration; - mWorkDuration = workDuration; - mEarliestVsync = earliestVsync; - mArmedInfo = {nextWakeupTime, nextVsyncTime}; + auto const nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration; + auto const nextReadyTime = nextVsyncTime - timing.readyDuration; + mScheduleTiming = timing; + mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime}; return ScheduleResult::Scheduled; } -void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(nsecs_t workDuration, - nsecs_t earliestVsync) { - mWorkloadUpdateInfo = {.earliestVsync = earliestVsync, .duration = workDuration}; +void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming timing) { + mWorkloadUpdateInfo = timing; } bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const { @@ -102,14 +106,18 @@ void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) { } if (mWorkloadUpdateInfo) { - mEarliestVsync = mWorkloadUpdateInfo->earliestVsync; - mWorkDuration = mWorkloadUpdateInfo->duration; + mScheduleTiming = *mWorkloadUpdateInfo; mWorkloadUpdateInfo.reset(); } - auto const nextVsyncTime = - tracker.nextAnticipatedVSyncTimeFrom(std::max(mEarliestVsync, now + mWorkDuration)); - mArmedInfo = {nextVsyncTime - mWorkDuration, nextVsyncTime}; + const auto earliestReadyBy = now + mScheduleTiming.workDuration + mScheduleTiming.readyDuration; + const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.earliestVsync); + + const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(earliestVsync); + const auto nextReadyTime = nextVsyncTime - mScheduleTiming.readyDuration; + const auto nextWakeupTime = nextReadyTime - mScheduleTiming.workDuration; + + mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime}; } void VSyncDispatchTimerQueueEntry::disarm() { @@ -122,13 +130,14 @@ nsecs_t VSyncDispatchTimerQueueEntry::executing() { return *mLastDispatchTime; } -void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp) { +void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp, + nsecs_t deadlineTimestamp) { { std::lock_guard lk(mRunningMutex); mRunning = true; } - mCallback(vsyncTimestamp, wakeupTimestamp); + mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp); std::lock_guard lk(mRunningMutex); mRunning = false; @@ -144,15 +153,20 @@ void VSyncDispatchTimerQueueEntry::dump(std::string& result) const { std::lock_guard lk(mRunningMutex); std::string armedInfo; if (mArmedInfo) { - StringAppendF(&armedInfo, "[wake up in %.2fms for vsync %.2fms from now]", + StringAppendF(&armedInfo, + "[wake up in %.2fms deadline in %.2fms for vsync %.2fms from now]", (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f, + (mArmedInfo->mActualReadyTime - systemTime()) / 1e6f, (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f); } StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(), mRunning ? "(in callback function)" : "", armedInfo.c_str()); - StringAppendF(&result, "\t\t\tmWorkDuration: %.2fms mEarliestVsync: %.2fms relative to now\n", - mWorkDuration / 1e6f, (mEarliestVsync - systemTime()) / 1e6f); + StringAppendF(&result, + "\t\t\tworkDuration: %.2fms readyDuration: %.2fms earliestVsync: %.2fms relative " + "to now\n", + mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f, + (mScheduleTiming.earliestVsync - systemTime()) / 1e6f); if (mLastDispatchTime) { StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n", @@ -239,6 +253,7 @@ void VSyncDispatchTimerQueue::timerCallback() { std::shared_ptr callback; nsecs_t vsyncTimestamp; nsecs_t wakeupTimestamp; + nsecs_t deadlineTimestamp; }; std::vector invocations; { @@ -252,11 +267,13 @@ void VSyncDispatchTimerQueue::timerCallback() { continue; } + auto const readyTime = callback->readyTime(); + auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast(0)); if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) { callback->executing(); - invocations.emplace_back( - Invocation{callback, *callback->lastExecutedVsyncTarget(), *wakeupTime}); + invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(), + *wakeupTime, *readyTime}); } } @@ -265,7 +282,8 @@ void VSyncDispatchTimerQueue::timerCallback() { } for (auto const& invocation : invocations) { - invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp); + invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp, + invocation.deadlineTimestamp); } } @@ -297,8 +315,8 @@ void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) { } } -ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t workDuration, - nsecs_t earliestVsync) { +ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, + ScheduleTiming scheduleTiming) { auto result = ScheduleResult::Error; { std::lock_guard lk(mMutex); @@ -314,11 +332,11 @@ ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t wo * timer recalculation to avoid cancelling a callback that is about to fire. */ auto const rearmImminent = now > mIntendedWakeupTime; if (CC_UNLIKELY(rearmImminent)) { - callback->addPendingWorkloadUpdate(workDuration, earliestVsync); + callback->addPendingWorkloadUpdate(scheduleTiming); return ScheduleResult::Scheduled; } - result = callback->schedule(workDuration, earliestVsync, mTracker, now); + result = callback->schedule(scheduleTiming, mTracker, now); if (result == ScheduleResult::CannotSchedule) { return result; } @@ -396,11 +414,11 @@ VSyncCallbackRegistration::~VSyncCallbackRegistration() { if (mValidToken) mDispatch.get().unregisterCallback(mToken); } -ScheduleResult VSyncCallbackRegistration::schedule(nsecs_t workDuration, nsecs_t earliestVsync) { +ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) { if (!mValidToken) { return ScheduleResult::Error; } - return mDispatch.get().schedule(mToken, workDuration, earliestVsync); + return mDispatch.get().schedule(mToken, scheduleTiming); } CancelResult VSyncCallbackRegistration::cancel() { diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h index 957c0d1eca..26237b63a3 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h @@ -47,7 +47,7 @@ public: std::optional lastExecutedVsyncTarget() const; // This moves the state from disarmed->armed and will calculate the wakeupTime. - ScheduleResult schedule(nsecs_t workDuration, nsecs_t earliestVsync, VSyncTracker& tracker, + ScheduleResult schedule(VSyncDispatch::ScheduleTiming timing, VSyncTracker& tracker, nsecs_t now); // This will update armed entries with the latest vsync information. Entry remains armed. void update(VSyncTracker& tracker, nsecs_t now); @@ -56,6 +56,8 @@ public: // It will not update the wakeupTime. std::optional wakeupTime() const; + std::optional readyTime() const; + std::optional targetVsync() const; // This moves state from armed->disarmed. @@ -67,14 +69,14 @@ public: // Adds a pending upload of the earliestVSync and workDuration that will be applied on the next // call to update() - void addPendingWorkloadUpdate(nsecs_t workDuration, nsecs_t earliestVsync); + void addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming); // Checks if there is a pending update to the workload, returning true if so. bool hasPendingWorkloadUpdate() const; // End: functions that are not threadsafe. // Invoke the callback with the two given timestamps, moving the state from running->disarmed. - void callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp); + void callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp, nsecs_t deadlineTimestamp); // Block calling thread while the callback is executing. void ensureNotRunning(); @@ -84,22 +86,18 @@ private: std::string const mName; VSyncDispatch::Callback const mCallback; - nsecs_t mWorkDuration; - nsecs_t mEarliestVsync; + VSyncDispatch::ScheduleTiming mScheduleTiming; nsecs_t const mMinVsyncDistance; struct ArmingInfo { nsecs_t mActualWakeupTime; nsecs_t mActualVsyncTime; + nsecs_t mActualReadyTime; }; std::optional mArmedInfo; std::optional mLastDispatchTime; - struct WorkloadUpdateInfo { - nsecs_t duration; - nsecs_t earliestVsync; - }; - std::optional mWorkloadUpdateInfo; + std::optional mWorkloadUpdateInfo; mutable std::mutex mRunningMutex; std::condition_variable mCv; @@ -125,7 +123,7 @@ public: CallbackToken registerCallback(Callback const& callbackFn, std::string callbackName) final; void unregisterCallback(CallbackToken token) final; - ScheduleResult schedule(CallbackToken token, nsecs_t workDuration, nsecs_t earliestVsync) final; + ScheduleResult schedule(CallbackToken token, ScheduleTiming scheduleTiming) final; CancelResult cancel(CallbackToken token) final; void dump(std::string& result) const final; diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index 61f3fbbdf1..e90edf77a2 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 #include "VSyncPredictor.h" @@ -54,7 +50,7 @@ inline void VSyncPredictor::traceInt64If(const char* name, int64_t value) const } } -inline size_t VSyncPredictor::next(int i) const { +inline size_t VSyncPredictor::next(size_t i) const { return (i + 1) % mTimestamps.size(); } @@ -69,12 +65,12 @@ bool VSyncPredictor::validate(nsecs_t timestamp) const { } nsecs_t VSyncPredictor::currentPeriod() const { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); return std::get<0>(mRateMap.find(mIdealPeriod)->second); } bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); if (!validate(timestamp)) { // VSR could elect to ignore the incongruent timestamp or resetModel(). If ts is ignored, @@ -138,14 +134,14 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { auto meanTS = scheduler::calculate_mean(vsyncTS); auto meanOrdinal = scheduler::calculate_mean(ordinals); - for (auto i = 0; i < vsyncTS.size(); i++) { + for (size_t i = 0; i < vsyncTS.size(); i++) { vsyncTS[i] -= meanTS; ordinals[i] -= meanOrdinal; } auto top = 0ll; auto bottom = 0ll; - for (auto i = 0; i < vsyncTS.size(); i++) { + for (size_t i = 0; i < vsyncTS.size(); i++) { top += vsyncTS[i] * ordinals[i]; bottom += ordinals[i] * ordinals[i]; } @@ -177,9 +173,9 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { } nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); - auto const [slope, intercept] = getVSyncPredictionModel(lk); + auto const [slope, intercept] = getVSyncPredictionModel(lock); if (mTimestamps.empty()) { traceInt64If("VSP-mode", 1); @@ -215,8 +211,8 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { } std::tuple VSyncPredictor::getVSyncPredictionModel() const { - std::lock_guard lk(mMutex); - return VSyncPredictor::getVSyncPredictionModel(lk); + std::lock_guard lock(mMutex); + return VSyncPredictor::getVSyncPredictionModel(lock); } std::tuple VSyncPredictor::getVSyncPredictionModel( @@ -227,7 +223,7 @@ std::tuple VSyncPredictor::getVSyncPredictionModel( void VSyncPredictor::setPeriod(nsecs_t period) { ATRACE_CALL(); - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); static constexpr size_t kSizeLimit = 30; if (CC_UNLIKELY(mRateMap.size() == kSizeLimit)) { mRateMap.erase(mRateMap.begin()); @@ -256,18 +252,18 @@ void VSyncPredictor::clearTimestamps() { } bool VSyncPredictor::needsMoreSamples() const { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); return mTimestamps.size() < kMinimumSamplesForPrediction; } void VSyncPredictor::resetModel() { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); mRateMap[mIdealPeriod] = {mIdealPeriod, 0}; clearTimestamps(); } void VSyncPredictor::dump(std::string& result) const { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); StringAppendF(&result, "\tmIdealPeriod=%.2f\n", mIdealPeriod / 1e6f); StringAppendF(&result, "\tRefresh Rate Map:\n"); for (const auto& [idealPeriod, periodInterceptTuple] : mRateMap) { @@ -280,5 +276,3 @@ void VSyncPredictor::dump(std::string& result) const { } // namespace android::scheduler -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h index 5f3c418fed..5f2ec492b7 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.h +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h @@ -74,7 +74,7 @@ private: size_t const kOutlierTolerancePercent; std::mutex mutable mMutex; - size_t next(int i) const REQUIRES(mMutex); + size_t next(size_t i) const REQUIRES(mMutex); bool validate(nsecs_t timestamp) const REQUIRES(mMutex); std::tuple getVSyncPredictionModel(std::lock_guard const&) const REQUIRES(mMutex); @@ -84,7 +84,7 @@ private: std::unordered_map> mutable mRateMap GUARDED_BY(mMutex); - int mLastTimestampIndex GUARDED_BY(mMutex) = 0; + size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0; std::vector mTimestamps GUARDED_BY(mMutex); }; diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index a2b279bd57..792313efee 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -38,20 +38,20 @@ nsecs_t SystemClock::now() const { class PredictedVsyncTracer { public: PredictedVsyncTracer(VSyncDispatch& dispatch) - : mRegistration(dispatch, - std::bind(&PredictedVsyncTracer::callback, this, std::placeholders::_1, - std::placeholders::_2), + : mRegistration(dispatch, std::bind(&PredictedVsyncTracer::callback, this), "PredictedVsyncTracer") { - mRegistration.schedule(0, 0); + scheduleRegistration(); } private: TracedOrdinal mParity = {"VSYNC-predicted", 0}; VSyncCallbackRegistration mRegistration; - void callback(nsecs_t /*vsyncTime*/, nsecs_t /*targetWakeupTim*/) { + void scheduleRegistration() { mRegistration.schedule({0, 0, 0}); } + + void callback() { mParity = !mParity; - mRegistration.schedule(0, 0); + scheduleRegistration(); } }; @@ -69,96 +69,6 @@ VSyncReactor::VSyncReactor(std::unique_ptr clock, VSyncDispatch& dispatch VSyncReactor::~VSyncReactor() = default; -// The DispSync interface has a 'repeat this callback at rate' semantic. This object adapts -// VSyncDispatch's individually-scheduled callbacks so as to meet DispSync's existing semantic -// for now. -class CallbackRepeater { -public: - CallbackRepeater(VSyncDispatch& dispatch, DispSync::Callback* cb, const char* name, - nsecs_t period, nsecs_t offset, nsecs_t notBefore) - : mName(name), - mCallback(cb), - mRegistration(dispatch, - std::bind(&CallbackRepeater::callback, this, std::placeholders::_1, - std::placeholders::_2), - mName), - mPeriod(period), - mOffset(offset), - mLastCallTime(notBefore) {} - - ~CallbackRepeater() { - std::lock_guard lk(mMutex); - mRegistration.cancel(); - } - - void start(nsecs_t offset) { - std::lock_guard lk(mMutex); - mStopped = false; - mOffset = offset; - - auto const schedule_result = mRegistration.schedule(calculateWorkload(), mLastCallTime); - LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled), - "Error scheduling callback: rc %X", schedule_result); - } - - void setPeriod(nsecs_t period) { - std::lock_guard lk(mMutex); - if (period == mPeriod) { - return; - } - mPeriod = period; - } - - void stop() { - std::lock_guard lk(mMutex); - LOG_ALWAYS_FATAL_IF(mStopped, "DispSyncInterface misuse: callback already stopped"); - mStopped = true; - mRegistration.cancel(); - } - - void dump(std::string& result) const { - std::lock_guard lk(mMutex); - StringAppendF(&result, "\t%s: mPeriod=%.2f last vsync time %.2fms relative to now (%s)\n", - mName.c_str(), mPeriod / 1e6f, (mLastCallTime - systemTime()) / 1e6f, - mStopped ? "stopped" : "running"); - } - -private: - void callback(nsecs_t vsynctime, nsecs_t wakeupTime) { - { - std::lock_guard lk(mMutex); - mLastCallTime = vsynctime; - } - - mCallback->onDispSyncEvent(wakeupTime, vsynctime); - - { - std::lock_guard lk(mMutex); - if (mStopped) { - return; - } - auto const schedule_result = mRegistration.schedule(calculateWorkload(), vsynctime); - LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled), - "Error rescheduling callback: rc %X", schedule_result); - } - } - - // DispSync offsets are defined as time after the vsync before presentation. - // VSyncReactor workloads are defined as time before the intended presentation vsync. - // Note change in sign between the two defnitions. - nsecs_t calculateWorkload() REQUIRES(mMutex) { return mPeriod - mOffset; } - - const std::string mName; - DispSync::Callback* const mCallback; - - std::mutex mutable mMutex; - VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex); - bool mStopped GUARDED_BY(mMutex) = false; - nsecs_t mPeriod GUARDED_BY(mMutex); - nsecs_t mOffset GUARDED_BY(mMutex); - nsecs_t mLastCallTime GUARDED_BY(mMutex); -}; - bool VSyncReactor::addPresentFence(const std::shared_ptr& fence) { if (!fence) { return false; @@ -169,7 +79,7 @@ bool VSyncReactor::addPresentFence(const std::shared_ptr& fence) { return true; } - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); if (mExternalIgnoreFences || mInternalIgnoreFences) { return true; } @@ -207,7 +117,7 @@ bool VSyncReactor::addPresentFence(const std::shared_ptr& fence) { } void VSyncReactor::setIgnorePresentFences(bool ignoration) { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); mExternalIgnoreFences = ignoration; updateIgnorePresentFencesInternal(); } @@ -269,8 +179,6 @@ void VSyncReactor::beginResync() { mTracker.resetModel(); } -void VSyncReactor::endResync() {} - bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp, std::optional HwcVsyncPeriod) { if (!mPeriodConfirmationInProgress) { return false; @@ -303,14 +211,11 @@ bool VSyncReactor::addResyncSample(nsecs_t timestamp, std::optional hwc bool* periodFlushed) { assert(periodFlushed); - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); if (periodConfirmed(timestamp, hwcVsyncPeriod)) { ATRACE_NAME("VSR: period confirmed"); if (mPeriodTransitioningTo) { mTracker.setPeriod(*mPeriodTransitioningTo); - for (auto& entry : mCallbacks) { - entry.second->setPeriod(*mPeriodTransitioningTo); - } *periodFlushed = true; } @@ -339,51 +244,8 @@ bool VSyncReactor::addResyncSample(nsecs_t timestamp, std::optional hwc return mMoreSamplesNeeded; } -status_t VSyncReactor::addEventListener(const char* name, nsecs_t phase, - DispSync::Callback* callback, - nsecs_t /* lastCallbackTime */) { - std::lock_guard lk(mMutex); - auto it = mCallbacks.find(callback); - if (it == mCallbacks.end()) { - // TODO (b/146557561): resolve lastCallbackTime semantics in DispSync i/f. - static auto constexpr maxListeners = 4; - if (mCallbacks.size() >= maxListeners) { - ALOGE("callback %s not added, exceeded callback limit of %i (currently %zu)", name, - maxListeners, mCallbacks.size()); - return NO_MEMORY; - } - - auto const period = mTracker.currentPeriod(); - auto repeater = std::make_unique(mDispatch, callback, name, period, phase, - mClock->now()); - it = mCallbacks.emplace(std::pair(callback, std::move(repeater))).first; - } - - it->second->start(phase); - return NO_ERROR; -} - -status_t VSyncReactor::removeEventListener(DispSync::Callback* callback, - nsecs_t* /* outLastCallback */) { - std::lock_guard lk(mMutex); - auto const it = mCallbacks.find(callback); - LOG_ALWAYS_FATAL_IF(it == mCallbacks.end(), "callback %p not registered", callback); - - it->second->stop(); - return NO_ERROR; -} - -status_t VSyncReactor::changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) { - std::lock_guard lk(mMutex); - auto const it = mCallbacks.find(callback); - LOG_ALWAYS_FATAL_IF(it == mCallbacks.end(), "callback was %p not registered", callback); - - it->second->start(phase); - return NO_ERROR; -} - void VSyncReactor::dump(std::string& result) const { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); StringAppendF(&result, "VsyncReactor in use\n"); StringAppendF(&result, "Has %zu unfired fences\n", mUnfiredFences.size()); StringAppendF(&result, "mInternalIgnoreFences=%d mExternalIgnoreFences=%d\n", @@ -403,17 +265,10 @@ void VSyncReactor::dump(std::string& result) const { StringAppendF(&result, "No Last HW vsync\n"); } - StringAppendF(&result, "CallbackRepeaters:\n"); - for (const auto& [callback, repeater] : mCallbacks) { - repeater->dump(result); - } - StringAppendF(&result, "VSyncTracker:\n"); mTracker.dump(result); StringAppendF(&result, "VSyncDispatch:\n"); mDispatch.dump(result); } -void VSyncReactor::reset() {} - } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index 22ceb3941b..c6f2777cbd 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -29,7 +29,6 @@ namespace android::scheduler { class Clock; class VSyncDispatch; class VSyncTracker; -class CallbackRepeater; class PredictedVsyncTracer; // TODO (b/145217110): consider renaming. @@ -52,15 +51,8 @@ public: void beginResync() final; bool addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, bool* periodFlushed) final; - void endResync() final; - - status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback, - nsecs_t lastCallbackTime) final; - status_t removeEventListener(DispSync::Callback* callback, nsecs_t* outLastCallback) final; - status_t changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) final; void dump(std::string& result) const final; - void reset() final; private: void setIgnorePresentFencesInternal(bool ignoration) REQUIRES(mMutex); @@ -85,9 +77,6 @@ private: std::optional mPeriodTransitioningTo GUARDED_BY(mMutex); std::optional mLastHwVsync GUARDED_BY(mMutex); - std::unordered_map> mCallbacks - GUARDED_BY(mMutex); - const std::unique_ptr mPredictedVsyncTracer; const bool mSupportKernelIdleTimer = false; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2b642a2590..b30b0ec18f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1452,7 +1452,11 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { status_t SurfaceFlinger::injectVSync(nsecs_t when) { Mutex::Autolock lock(mStateLock); - return mScheduler->injectVSync(when, calculateExpectedPresentTime(when)) ? NO_ERROR : BAD_VALUE; + const auto expectedPresent = calculateExpectedPresentTime(when); + return mScheduler->injectVSync(when, /*expectedVSyncTime=*/expectedPresent, + /*deadlineTimestamp=*/expectedPresent) + ? NO_ERROR + : BAD_VALUE; } status_t SurfaceFlinger::getLayerDebugInfo(std::vector* outLayers) { @@ -2984,14 +2988,16 @@ void SurfaceFlinger::initScheduler(PhysicalDisplayId primaryDisplayId) { // start the EventThread mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this); + const auto configs = mVsyncConfiguration->getCurrentConfigs(); mAppConnectionHandle = mScheduler->createConnection("app", - mVsyncConfiguration->getCurrentConfigs().late.appOffset, + /*workDuration=*/configs.late.appWorkDuration, + /*readyDuration=*/configs.late.sfWorkDuration, impl::EventThread::InterceptVSyncsCallback()); mSfConnectionHandle = mScheduler->createConnection("sf", - mVsyncConfiguration->getCurrentConfigs().late.sfOffset, - [this](nsecs_t timestamp) { + /*workDuration=*/configs.late.sfWorkDuration, + /*readyDuration=*/0ns, [this](nsecs_t timestamp) { mInterceptor->saveVSyncEvent(timestamp); }); @@ -3024,8 +3030,12 @@ void SurfaceFlinger::updatePhaseConfiguration(const RefreshRate& refreshRate) { } void SurfaceFlinger::setVsyncConfig(const VsyncModulator::VsyncConfig& config) { - mScheduler->setPhaseOffset(mAppConnectionHandle, config.appOffset); - mScheduler->setPhaseOffset(mSfConnectionHandle, config.sfOffset); + mScheduler->setDuration(mAppConnectionHandle, + /*workDuration=*/config.appWorkDuration, + /*readyDuration=*/config.sfWorkDuration); + mScheduler->setDuration(mSfConnectionHandle, + /*workDuration=*/config.sfWorkDuration, + /*readyDuration=*/0ns); } void SurfaceFlinger::commitTransaction() { @@ -5170,14 +5180,14 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r mForceFullDamage = n != 0; return NO_ERROR; } - case 1018: { // Modify Choreographer's phase offset + case 1018: { // Modify Choreographer's duration n = data.readInt32(); - mScheduler->setPhaseOffset(mAppConnectionHandle, static_cast(n)); + mScheduler->setDuration(mAppConnectionHandle, std::chrono::nanoseconds(n), 0ns); return NO_ERROR; } - case 1019: { // Modify SurfaceFlinger's phase offset + case 1019: { // Modify SurfaceFlinger's duration n = data.readInt32(); - mScheduler->setPhaseOffset(mSfConnectionHandle, static_cast(n)); + mScheduler->setDuration(mSfConnectionHandle, std::chrono::nanoseconds(n), 0ns); return NO_ERROR; } case 1020: { // Layer updates interceptor diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h index 4e7f67d5ac..49cf80cc68 100644 --- a/services/surfaceflinger/TracedOrdinal.h +++ b/services/surfaceflinger/TracedOrdinal.h @@ -21,12 +21,32 @@ #include #include +namespace std { +template +bool signbit(std::chrono::duration v) { + return signbit(std::chrono::duration_cast(v).count()); +} +} // namespace std + namespace android { +namespace { +template +int64_t to_int64(T v) { + return int64_t(v); +} + +template +int64_t to_int64(std::chrono::duration v) { + return int64_t(v.count()); +} +} // namespace + template class TracedOrdinal { public: - static_assert(std::is_same() || (std::is_signed() && std::is_integral()), + static_assert(std::is_same() || (std::is_signed() && std::is_integral()) || + std::is_same(), "Type is not supported. Please test it with systrace before adding " "it to the list."); @@ -57,12 +77,12 @@ private: } if (!std::signbit(mData)) { - ATRACE_INT64(mName.c_str(), int64_t(mData)); + ATRACE_INT64(mName.c_str(), to_int64(mData)); if (mHasGoneNegative) { ATRACE_INT64(mNameNegative.c_str(), 0); } } else { - ATRACE_INT64(mNameNegative.c_str(), -int64_t(mData)); + ATRACE_INT64(mNameNegative.c_str(), -to_int64(mData)); ATRACE_INT64(mName.c_str(), 0); } } diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp index afebc40aa9..54f4c7c018 100644 --- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp +++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp @@ -27,13 +27,99 @@ #include "AsyncCallRecorder.h" #include "Scheduler/DispSyncSource.h" -#include "mock/MockDispSync.h" +#include "Scheduler/VSyncDispatch.h" namespace android { namespace { using namespace std::chrono_literals; -using testing::Return; +using namespace testing; + +class MockVSyncDispatch : public scheduler::VSyncDispatch { +public: + MOCK_METHOD2(registerCallback, + CallbackToken(std::function const&, std::string)); + MOCK_METHOD1(unregisterCallback, void(CallbackToken)); + MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming)); + MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token)); + MOCK_CONST_METHOD1(dump, void(std::string&)); + + MockVSyncDispatch() { + ON_CALL(*this, registerCallback) + .WillByDefault( + [this](std::function const& callback, + std::string) { + CallbackToken token(mNextToken); + mNextToken++; + + mCallbacks.emplace(token, CallbackData(callback)); + ALOGD("registerCallback: %zu", token.value()); + return token; + }); + + ON_CALL(*this, unregisterCallback).WillByDefault([this](CallbackToken token) { + ALOGD("unregisterCallback: %zu", token.value()); + mCallbacks.erase(token); + }); + + ON_CALL(*this, schedule).WillByDefault([this](CallbackToken token, ScheduleTiming timing) { + ALOGD("schedule: %zu", token.value()); + if (mCallbacks.count(token) == 0) { + ALOGD("schedule: callback %zu not registered", token.value()); + return scheduler::ScheduleResult::Error; + } + + auto& callback = mCallbacks.at(token); + callback.scheduled = true; + callback.vsyncTime = timing.earliestVsync; + callback.targetWakeupTime = + timing.earliestVsync - timing.workDuration - timing.readyDuration; + ALOGD("schedule: callback %zu scheduled", token.value()); + return scheduler::ScheduleResult::Scheduled; + }); + + ON_CALL(*this, cancel).WillByDefault([this](CallbackToken token) { + ALOGD("cancel: %zu", token.value()); + if (mCallbacks.count(token) == 0) { + ALOGD("cancel: callback %zu is not registered", token.value()); + return scheduler::CancelResult::Error; + } + + auto& callback = mCallbacks.at(token); + callback.scheduled = false; + ALOGD("cancel: callback %zu cancelled", token.value()); + return scheduler::CancelResult::Cancelled; + }); + } + + void triggerCallbacks() { + ALOGD("triggerCallbacks"); + for (auto& [token, callback] : mCallbacks) { + if (callback.scheduled) { + ALOGD("triggerCallbacks: callback %zu", token.value()); + callback.scheduled = false; + callback.func(callback.vsyncTime, callback.targetWakeupTime, callback.readyTime); + } else { + ALOGD("triggerCallbacks: callback %zu is not scheduled", token.value()); + } + } + } + +private: + struct CallbackData { + explicit CallbackData(std::function func) + : func(std::move(func)) {} + + std::function func; + bool scheduled = false; + nsecs_t vsyncTime = 0; + nsecs_t targetWakeupTime = 0; + nsecs_t readyTime = 0; + }; + + std::unordered_map mCallbacks; + size_t mNextToken; +}; class DispSyncSourceTest : public testing::Test, private VSyncSource::Callback { protected: @@ -43,15 +129,19 @@ protected: void createDispSync(); void createDispSyncSource(); - void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override; + void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) override; - std::unique_ptr mDispSync; - std::unique_ptr mDispSyncSource; + std::unique_ptr mVSyncDispatch; + std::unique_ptr mDispSyncSource; - AsyncCallRecorder mVSyncEventCallRecorder; + AsyncCallRecorder mVSyncEventCallRecorder; - static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms; + static constexpr std::chrono::nanoseconds mWorkDuration = 20ms; + static constexpr std::chrono::nanoseconds mReadyDuration = 10ms; static constexpr int mIterations = 100; + const scheduler::VSyncDispatch::CallbackToken mFakeToken{2398}; + const std::string mName = "DispSyncSourceTest"; }; DispSyncSourceTest::DispSyncSourceTest() { @@ -66,20 +156,21 @@ DispSyncSourceTest::~DispSyncSourceTest() { ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } -void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) { +void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) { ALOGD("onVSyncEvent: %" PRId64, when); - mVSyncEventCallRecorder.recordCall(when); + mVSyncEventCallRecorder.recordCall(when, expectedVSyncTimestamp, deadlineTimestamp); } void DispSyncSourceTest::createDispSync() { - mDispSync = std::make_unique(); + mVSyncDispatch = std::make_unique(); } void DispSyncSourceTest::createDispSyncSource() { - createDispSync(); - mDispSyncSource = std::make_unique(mDispSync.get(), mPhaseOffset.count(), true, - "DispSyncSourceTest"); + mDispSyncSource = + std::make_unique(*mVSyncDispatch, mWorkDuration, + mReadyDuration, true, mName.c_str()); mDispSyncSource->setCallback(this); } @@ -89,57 +180,119 @@ void DispSyncSourceTest::createDispSyncSource() { TEST_F(DispSyncSourceTest, createDispSync) { createDispSync(); - EXPECT_TRUE(mDispSync); + EXPECT_TRUE(mVSyncDispatch); } TEST_F(DispSyncSourceTest, createDispSyncSource) { + createDispSync(); + + InSequence seq; + EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).WillOnce(Return(mFakeToken)); + EXPECT_CALL(*mVSyncDispatch, cancel(mFakeToken)) + .WillOnce(Return(scheduler::CancelResult::Cancelled)); + EXPECT_CALL(*mVSyncDispatch, unregisterCallback(mFakeToken)).WillOnce(Return()); createDispSyncSource(); + EXPECT_TRUE(mDispSyncSource); } TEST_F(DispSyncSourceTest, noCallbackAfterInit) { + createDispSync(); + + InSequence seq; + EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1); + EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1); + EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1); createDispSyncSource(); + EXPECT_TRUE(mDispSyncSource); // DispSyncSource starts with Vsync disabled - mDispSync->triggerCallback(); + mVSyncDispatch->triggerCallbacks(); EXPECT_FALSE(mVSyncEventCallRecorder.waitForUnexpectedCall().has_value()); } TEST_F(DispSyncSourceTest, waitForCallbacks) { + createDispSync(); + + InSequence seq; + EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1); + EXPECT_CALL(*mVSyncDispatch, + schedule(_, Truly([&](auto timings) { + return timings.workDuration == mWorkDuration.count() && + timings.readyDuration == mReadyDuration.count(); + }))) + .Times(mIterations + 1); + EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1); + EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1); createDispSyncSource(); + EXPECT_TRUE(mDispSyncSource); mDispSyncSource->setVSyncEnabled(true); - EXPECT_EQ(mDispSync->getCallbackPhase(), mPhaseOffset.count()); - for (int i = 0; i < mIterations; i++) { - mDispSync->triggerCallback(); - EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value()); + mVSyncDispatch->triggerCallbacks(); + const auto callbackData = mVSyncEventCallRecorder.waitForCall(); + ASSERT_TRUE(callbackData.has_value()); + const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value(); + EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count()); } } -TEST_F(DispSyncSourceTest, waitForCallbacksWithPhaseChange) { +TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) { + createDispSync(); + + InSequence seq; + EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1); + EXPECT_CALL(*mVSyncDispatch, + schedule(_, Truly([&](auto timings) { + return timings.workDuration == mWorkDuration.count() && + timings.readyDuration == mReadyDuration.count(); + }))) + .Times(1); + createDispSyncSource(); + EXPECT_TRUE(mDispSyncSource); mDispSyncSource->setVSyncEnabled(true); - EXPECT_EQ(mDispSync->getCallbackPhase(), mPhaseOffset.count()); - + EXPECT_CALL(*mVSyncDispatch, + schedule(_, Truly([&](auto timings) { + return timings.workDuration == mWorkDuration.count() && + timings.readyDuration == mReadyDuration.count(); + }))) + .Times(mIterations); for (int i = 0; i < mIterations; i++) { - mDispSync->triggerCallback(); - EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value()); + mVSyncDispatch->triggerCallbacks(); + const auto callbackData = mVSyncEventCallRecorder.waitForCall(); + ASSERT_TRUE(callbackData.has_value()); + const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value(); + EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count()); } - EXPECT_CALL(*mDispSync, getPeriod()).Times(1).WillOnce(Return(16666666)); - mDispSyncSource->setPhaseOffset((mPhaseOffset / 2).count()); - - EXPECT_EQ(mDispSync->getCallbackPhase(), (mPhaseOffset / 2).count()); - + const auto newDuration = mWorkDuration / 2; + EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) { + return timings.workDuration == newDuration.count() && + timings.readyDuration == 0; + }))) + .Times(1); + mDispSyncSource->setDuration(newDuration, 0ns); + + EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) { + return timings.workDuration == newDuration.count() && + timings.readyDuration == 0; + }))) + .Times(mIterations); for (int i = 0; i < mIterations; i++) { - mDispSync->triggerCallback(); - EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value()); + mVSyncDispatch->triggerCallbacks(); + const auto callbackData = mVSyncEventCallRecorder.waitForCall(); + ASSERT_TRUE(callbackData.has_value()); + const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value(); + EXPECT_EQ(when, expectedVSyncTimestamp - newDuration.count()); } + + EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1); + EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 7fade0dec2..b9c9fe7686 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -1325,8 +1325,6 @@ TEST_F(DisplayTransactionTest, resetDisplayStateClearsState) { // The call disable vsyncs EXPECT_CALL(mSchedulerCallback, setVsyncEnabled(false)).Times(1); - // The call ends any display resyncs - EXPECT_CALL(*mPrimaryDispSync, endResync()).Times(1); // -------------------------------------------------------------------- // Invocation @@ -3265,16 +3263,11 @@ struct DispSyncIsSupportedVariant { EXPECT_CALL(*test->mPrimaryDispSync, setPeriod(DEFAULT_REFRESH_RATE)).Times(1); EXPECT_CALL(*test->mPrimaryDispSync, beginResync()).Times(1); } - - static void setupEndResyncCallExpectations(DisplayTransactionTest* test) { - EXPECT_CALL(*test->mPrimaryDispSync, endResync()).Times(1); - } }; struct DispSyncNotSupportedVariant { static void setupBeginResyncCallExpectations(DisplayTransactionTest* /* test */) {} - static void setupEndResyncCallExpectations(DisplayTransactionTest* /* test */) {} }; // -------------------------------------------------------------------- @@ -3326,7 +3319,6 @@ struct TransitionOnToOffVariant : public TransitionVariantCommon static void setupCallExpectations(DisplayTransactionTest* test) { Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test); - Case::DispSync::setupEndResyncCallExpectations(test); Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF); } @@ -3389,7 +3381,6 @@ struct TransitionOnToDozeSuspendVariant template static void setupCallExpectations(DisplayTransactionTest* test) { Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test); - Case::DispSync::setupEndResyncCallExpectations(test); Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND); } }; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index aab6d01f01..ae94f16f5b 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -46,7 +46,9 @@ public: MOCK_METHOD1(setVSyncEnabled, void(bool)); MOCK_METHOD1(setCallback, void(VSyncSource::Callback*)); - MOCK_METHOD1(setPhaseOffset, void(nsecs_t)); + MOCK_METHOD2(setDuration, + void(std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration)); MOCK_METHOD1(pauseVsyncCallback, void(bool)); MOCK_CONST_METHOD1(dump, void(std::string&)); }; @@ -74,7 +76,8 @@ protected: ISurfaceComposer::ConfigChanged configChanged); void expectVSyncSetEnabledCallReceived(bool expectedState); - void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset); + void expectVSyncSetDurationCallReceived(std::chrono::nanoseconds expectedDuration, + std::chrono::nanoseconds expectedReadyDuration); VSyncSource::Callback* expectVSyncSetCallbackCallReceived(); void expectInterceptCallReceived(nsecs_t expectedTimestamp); void expectVsyncEventReceivedByConnection(const char* name, @@ -89,7 +92,8 @@ protected: AsyncCallRecorder mVSyncSetEnabledCallRecorder; AsyncCallRecorder mVSyncSetCallbackCallRecorder; - AsyncCallRecorder mVSyncSetPhaseOffsetCallRecorder; + AsyncCallRecorder + mVSyncSetDurationCallRecorder; AsyncCallRecorder mResyncCallRecorder; AsyncCallRecorder mInterceptVSyncCallRecorder; ConnectionEventRecorder mConnectionEventCallRecorder{0}; @@ -114,8 +118,8 @@ EventThreadTest::EventThreadTest() { EXPECT_CALL(*mVSyncSource, setCallback(_)) .WillRepeatedly(Invoke(mVSyncSetCallbackCallRecorder.getInvocable())); - EXPECT_CALL(*mVSyncSource, setPhaseOffset(_)) - .WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable())); + EXPECT_CALL(*mVSyncSource, setDuration(_, _)) + .WillRepeatedly(Invoke(mVSyncSetDurationCallRecorder.getInvocable())); createThread(std::move(vsyncSource)); mConnection = createConnection(mConnectionEventCallRecorder, @@ -159,10 +163,12 @@ void EventThreadTest::expectVSyncSetEnabledCallReceived(bool expectedState) { EXPECT_EQ(expectedState, std::get<0>(args.value())); } -void EventThreadTest::expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset) { - auto args = mVSyncSetPhaseOffsetCallRecorder.waitForCall(); +void EventThreadTest::expectVSyncSetDurationCallReceived( + std::chrono::nanoseconds expectedDuration, std::chrono::nanoseconds expectedReadyDuration) { + auto args = mVSyncSetDurationCallRecorder.waitForCall(); ASSERT_TRUE(args.has_value()); - EXPECT_EQ(expectedPhaseOffset, std::get<0>(args.value())); + EXPECT_EQ(expectedDuration, std::get<0>(args.value())); + EXPECT_EQ(expectedReadyDuration, std::get<1>(args.value())); } VSyncSource::Callback* EventThreadTest::expectVSyncSetCallbackCallReceived() { @@ -229,7 +235,7 @@ namespace { TEST_F(EventThreadTest, canCreateAndDestroyThreadWithNoEventsSent) { EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value()); EXPECT_FALSE(mVSyncSetCallbackCallRecorder.waitForCall(0us).has_value()); - EXPECT_FALSE(mVSyncSetPhaseOffsetCallRecorder.waitForCall(0us).has_value()); + EXPECT_FALSE(mVSyncSetDurationCallRecorder.waitForCall(0us).has_value()); EXPECT_FALSE(mResyncCallRecorder.waitForCall(0us).has_value()); EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall(0us).has_value()); EXPECT_FALSE(mConnectionEventCallRecorder.waitForCall(0us).has_value()); @@ -258,14 +264,14 @@ TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { // Use the received callback to signal a first vsync event. // The interceptor should receive the event, as well as the connection. - mCallback->onVSyncEvent(123, 456); + mCallback->onVSyncEvent(123, 456, 789); expectInterceptCallReceived(123); expectVsyncEventReceivedByConnection(123, 1u); // Use the received callback to signal a second vsync event. // The interceptor should receive the event, but the the connection should // not as it was only interested in the first. - mCallback->onVSyncEvent(456, 123); + mCallback->onVSyncEvent(456, 123, 0); expectInterceptCallReceived(456); EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value()); @@ -299,7 +305,7 @@ TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { // Send a vsync event. EventThread should then make a call to the // interceptor, and the second connection. The first connection should not // get the event. - mCallback->onVSyncEvent(123, 456); + mCallback->onVSyncEvent(123, 456, 0); expectInterceptCallReceived(123); EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value()); expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123, @@ -314,17 +320,17 @@ TEST_F(EventThreadTest, setVsyncRateOnePostsAllEventsToThatConnection) { // Send a vsync event. EventThread should then make a call to the // interceptor, and the connection. - mCallback->onVSyncEvent(123, 456); + mCallback->onVSyncEvent(123, 456, 789); expectInterceptCallReceived(123); expectVsyncEventReceivedByConnection(123, 1u); // A second event should go to the same places. - mCallback->onVSyncEvent(456, 123); + mCallback->onVSyncEvent(456, 123, 0); expectInterceptCallReceived(456); expectVsyncEventReceivedByConnection(456, 2u); // A third event should go to the same places. - mCallback->onVSyncEvent(789, 777); + mCallback->onVSyncEvent(789, 777, 111); expectInterceptCallReceived(789); expectVsyncEventReceivedByConnection(789, 3u); } @@ -336,22 +342,22 @@ TEST_F(EventThreadTest, setVsyncRateTwoPostsEveryOtherEventToThatConnection) { expectVSyncSetEnabledCallReceived(true); // The first event will be seen by the interceptor, and not the connection. - mCallback->onVSyncEvent(123, 456); + mCallback->onVSyncEvent(123, 456, 789); expectInterceptCallReceived(123); EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value()); // The second event will be seen by the interceptor and the connection. - mCallback->onVSyncEvent(456, 123); + mCallback->onVSyncEvent(456, 123, 0); expectInterceptCallReceived(456); expectVsyncEventReceivedByConnection(456, 2u); // The third event will be seen by the interceptor, and not the connection. - mCallback->onVSyncEvent(789, 777); + mCallback->onVSyncEvent(789, 777, 744); expectInterceptCallReceived(789); EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value()); // The fourth event will be seen by the interceptor and the connection. - mCallback->onVSyncEvent(101112, 7847); + mCallback->onVSyncEvent(101112, 7847, 86); expectInterceptCallReceived(101112); expectVsyncEventReceivedByConnection(101112, 4u); } @@ -366,7 +372,7 @@ TEST_F(EventThreadTest, connectionsRemovedIfInstanceDestroyed) { mConnection = nullptr; // The first event will be seen by the interceptor, and not the connection. - mCallback->onVSyncEvent(123, 456); + mCallback->onVSyncEvent(123, 456, 789); expectInterceptCallReceived(123); EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value()); @@ -386,13 +392,13 @@ TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) { // The first event will be seen by the interceptor, and by the connection, // which then returns an error. - mCallback->onVSyncEvent(123, 456); + mCallback->onVSyncEvent(123, 456, 789); expectInterceptCallReceived(123); expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u); // A subsequent event will be seen by the interceptor and not by the // connection. - mCallback->onVSyncEvent(456, 123); + mCallback->onVSyncEvent(456, 123, 0); expectInterceptCallReceived(456); EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value()); @@ -420,7 +426,7 @@ TEST_F(EventThreadTest, tracksEventConnections) { // The first event will be seen by the interceptor, and by the connection, // which then returns an error. - mCallback->onVSyncEvent(123, 456); + mCallback->onVSyncEvent(123, 456, 789); expectInterceptCallReceived(123); expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u); expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123, @@ -440,13 +446,13 @@ TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) { // The first event will be seen by the interceptor, and by the connection, // which then returns an non-fatal error. - mCallback->onVSyncEvent(123, 456); + mCallback->onVSyncEvent(123, 456, 789); expectInterceptCallReceived(123); expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u); // A subsequent event will be seen by the interceptor, and by the connection, // which still then returns an non-fatal error. - mCallback->onVSyncEvent(456, 123); + mCallback->onVSyncEvent(456, 123, 0); expectInterceptCallReceived(456); expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u); @@ -455,8 +461,8 @@ TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) { } TEST_F(EventThreadTest, setPhaseOffsetForwardsToVSyncSource) { - mThread->setPhaseOffset(321); - expectVSyncSetPhaseOffsetCallReceived(321); + mThread->setDuration(321ns, 456ns); + expectVSyncSetDurationCallReceived(321ns, 456ns); } TEST_F(EventThreadTest, postHotplugInternalDisconnect) { diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 39e793a83c..35619a38d7 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -120,8 +120,8 @@ TEST_F(SchedulerTest, invalidConnectionHandle) { mScheduler.dump(handle, output); EXPECT_TRUE(output.empty()); - EXPECT_CALL(*mEventThread, setPhaseOffset(_)).Times(0); - mScheduler.setPhaseOffset(handle, 10); + EXPECT_CALL(*mEventThread, setDuration(10ns, 20ns)).Times(0); + mScheduler.setDuration(handle, 10ns, 20ns); } TEST_F(SchedulerTest, validConnectionHandle) { @@ -146,8 +146,8 @@ TEST_F(SchedulerTest, validConnectionHandle) { mScheduler.dump(mConnectionHandle, output); EXPECT_FALSE(output.empty()); - EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1); - mScheduler.setPhaseOffset(mConnectionHandle, 10); + EXPECT_CALL(*mEventThread, setDuration(10ns, 20ns)).Times(1); + mScheduler.setDuration(mConnectionHandle, 10ns, 20ns); static constexpr size_t kEventConnections = 5; EXPECT_CALL(*mEventThread, getEventThreadConnectionCount()).WillOnce(Return(kEventConnections)); diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp index c2a77527a1..3408fed3e0 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp @@ -104,14 +104,18 @@ struct VSyncDispatchRealtimeTest : testing::Test { class RepeatingCallbackReceiver { public: - RepeatingCallbackReceiver(VSyncDispatch& dispatch, nsecs_t wl) - : mWorkload(wl), + RepeatingCallbackReceiver(VSyncDispatch& dispatch, nsecs_t workload, nsecs_t readyDuration) + : mWorkload(workload), + mReadyDuration(readyDuration), mCallback( - dispatch, [&](auto time, auto) { callback_called(time); }, "repeat0") {} + dispatch, [&](auto time, auto, auto) { callback_called(time); }, "repeat0") {} void repeatedly_schedule(size_t iterations, std::function const& onEachFrame) { mCallbackTimes.reserve(iterations); - mCallback.schedule(mWorkload, systemTime(SYSTEM_TIME_MONOTONIC) + mWorkload); + mCallback.schedule( + {.workDuration = mWorkload, + .readyDuration = mReadyDuration, + .earliestVsync = systemTime(SYSTEM_TIME_MONOTONIC) + mWorkload + mReadyDuration}); for (auto i = 0u; i < iterations - 1; i++) { std::unique_lock lk(mMutex); @@ -122,7 +126,9 @@ public: onEachFrame(last); - mCallback.schedule(mWorkload, last + mWorkload); + mCallback.schedule({.workDuration = mWorkload, + .readyDuration = mReadyDuration, + .earliestVsync = last + mWorkload + mReadyDuration}); } // wait for the last callback. @@ -144,6 +150,7 @@ private: } nsecs_t const mWorkload; + nsecs_t const mReadyDuration; VSyncCallbackRegistration mCallback; std::mutex mMutex; @@ -160,9 +167,9 @@ TEST_F(VSyncDispatchRealtimeTest, triple_alarm) { static size_t constexpr num_clients = 3; std::array - cb_receiver{RepeatingCallbackReceiver(dispatch, toNs(1500us)), - RepeatingCallbackReceiver(dispatch, toNs(0h)), - RepeatingCallbackReceiver(dispatch, toNs(1ms))}; + cb_receiver{RepeatingCallbackReceiver(dispatch, toNs(1500us), toNs(2500us)), + RepeatingCallbackReceiver(dispatch, toNs(0h), toNs(0h)), + RepeatingCallbackReceiver(dispatch, toNs(1ms), toNs(3ms))}; auto const on_each_frame = [](nsecs_t) {}; std::array threads{ @@ -187,7 +194,7 @@ TEST_F(VSyncDispatchRealtimeTest, vascillating_vrr) { VSyncDispatchTimerQueue dispatch(std::make_unique(), tracker, mDispatchGroupThreshold, mVsyncMoveThreshold); - RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms)); + RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms), toNs(5ms)); auto const on_each_frame = [&](nsecs_t last_known) { tracker.set_interval(next_vsync_interval += toNs(1ms), last_known); @@ -205,7 +212,7 @@ TEST_F(VSyncDispatchRealtimeTest, fixed_jump) { VSyncDispatchTimerQueue dispatch(std::make_unique(), tracker, mDispatchGroupThreshold, mVsyncMoveThreshold); - RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms)); + RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms), toNs(5ms)); auto jump_frame_counter = 0u; auto constexpr jump_frame_at = 10u; diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index f630e3bb46..24e243fe77 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -109,22 +109,24 @@ public: CountingCallback(VSyncDispatch& dispatch) : mDispatch(dispatch), mToken(dispatch.registerCallback(std::bind(&CountingCallback::counter, this, - std::placeholders::_1, - std::placeholders::_2), + std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3), "test")) {} ~CountingCallback() { mDispatch.unregisterCallback(mToken); } operator VSyncDispatch::CallbackToken() const { return mToken; } - void counter(nsecs_t time, nsecs_t wakeup_time) { + void counter(nsecs_t time, nsecs_t wakeup_time, nsecs_t readyTime) { mCalls.push_back(time); mWakeupTime.push_back(wakeup_time); + mReadyTime.push_back(readyTime); } VSyncDispatch& mDispatch; VSyncDispatch::CallbackToken mToken; std::vector mCalls; std::vector mWakeupTime; + std::vector mReadyTime; }; class PausingCallback { @@ -228,7 +230,11 @@ TEST_F(VSyncDispatchTimerQueueTest, unregistersSetAlarmOnDestruction) { VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold, mVsyncMoveThreshold}; CountingCallback cb(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 100, + .readyDuration = 0, + .earliestVsync = 1000}), + ScheduleResult::Scheduled); } } @@ -237,7 +243,11 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFuture) { EXPECT_CALL(mMockClock, alarmAt(_, 900)); CountingCallback cb(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb, 100, intended), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 100, + .readyDuration = 0, + .earliestVsync = intended}), + ScheduleResult::Scheduled); advanceToNextCallback(); ASSERT_THAT(cb.mCalls.size(), Eq(1)); @@ -249,7 +259,7 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithAdjustmentToTrueV EXPECT_CALL(mMockClock, alarmAt(_, 1050)); CountingCallback cb(mDispatch); - mDispatch.schedule(cb, 100, mPeriod); + mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod}); advanceToNextCallback(); ASSERT_THAT(cb.mCalls.size(), Eq(1)); @@ -265,7 +275,11 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingAdjustmentPast) { EXPECT_CALL(mMockClock, alarmAt(_, mPeriod)); CountingCallback cb(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb, workDuration, mPeriod), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = workDuration, + .readyDuration = 0, + .earliestVsync = mPeriod}), + ScheduleResult::Scheduled); } TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) { @@ -273,7 +287,11 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) { EXPECT_CALL(mMockClock, alarmCancel()); CountingCallback cb(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 100, + .readyDuration = 0, + .earliestVsync = mPeriod}), + ScheduleResult::Scheduled); EXPECT_EQ(mDispatch.cancel(cb), CancelResult::Cancelled); } @@ -282,7 +300,11 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLate) { EXPECT_CALL(mMockClock, alarmCancel()); CountingCallback cb(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 100, + .readyDuration = 0, + .earliestVsync = mPeriod}), + ScheduleResult::Scheduled); mMockClock.advanceBy(950); EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate); } @@ -292,7 +314,11 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLateWhenRunning) { EXPECT_CALL(mMockClock, alarmCancel()); PausingCallback cb(mDispatch, std::chrono::duration_cast(1s)); - EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 100, + .readyDuration = 0, + .earliestVsync = mPeriod}), + ScheduleResult::Scheduled); std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); }); EXPECT_TRUE(cb.waitForPause()); @@ -309,7 +335,11 @@ TEST_F(VSyncDispatchTimerQueueTest, unregisterSynchronizes) { PausingCallback cb(mDispatch, 50ms); cb.stashResource(resource); - EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 100, + .readyDuration = 0, + .earliestVsync = mPeriod}), + ScheduleResult::Scheduled); std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); }); EXPECT_TRUE(cb.waitForPause()); @@ -339,8 +369,8 @@ TEST_F(VSyncDispatchTimerQueueTest, basicTwoAlarmSetting) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch.schedule(cb0, 100, mPeriod); - mDispatch.schedule(cb1, 250, mPeriod); + mDispatch.schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod}); + mDispatch.schedule(cb1, {.workDuration = 250, .readyDuration = 0, .earliestVsync = mPeriod}); advanceToNextCallback(); advanceToNextCallback(); @@ -367,8 +397,9 @@ TEST_F(VSyncDispatchTimerQueueTest, rearmsFaroutTimeoutWhenCancellingCloseOne) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch.schedule(cb0, 100, mPeriod * 10); - mDispatch.schedule(cb1, 250, mPeriod); + mDispatch.schedule(cb0, + {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod * 10}); + mDispatch.schedule(cb1, {.workDuration = 250, .readyDuration = 0, .earliestVsync = mPeriod}); mDispatch.cancel(cb1); } @@ -380,9 +411,9 @@ TEST_F(VSyncDispatchTimerQueueTest, noUnnecessaryRearmsWhenRescheduling) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch.schedule(cb0, 400, 1000); - mDispatch.schedule(cb1, 200, 1000); - mDispatch.schedule(cb1, 300, 1000); + mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch.schedule(cb1, {.workDuration = 300, .readyDuration = 0, .earliestVsync = 1000}); advanceToNextCallback(); } @@ -395,9 +426,9 @@ TEST_F(VSyncDispatchTimerQueueTest, necessaryRearmsWhenModifying) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch.schedule(cb0, 400, 1000); - mDispatch.schedule(cb1, 200, 1000); - mDispatch.schedule(cb1, 500, 1000); + mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch.schedule(cb1, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); advanceToNextCallback(); } @@ -415,9 +446,10 @@ TEST_F(VSyncDispatchTimerQueueTest, modifyIntoGroup) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch.schedule(cb0, 400, 1000); - mDispatch.schedule(cb1, 200, 1000); - mDispatch.schedule(cb1, closeOffset, 1000); + mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch.schedule(cb1, + {.workDuration = closeOffset, .readyDuration = 0, .earliestVsync = 1000}); advanceToNextCallback(); ASSERT_THAT(cb0.mCalls.size(), Eq(1)); @@ -425,8 +457,9 @@ TEST_F(VSyncDispatchTimerQueueTest, modifyIntoGroup) { ASSERT_THAT(cb1.mCalls.size(), Eq(1)); EXPECT_THAT(cb1.mCalls[0], Eq(mPeriod)); - mDispatch.schedule(cb0, 400, 2000); - mDispatch.schedule(cb1, notCloseOffset, 2000); + mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 2000}); + mDispatch.schedule(cb1, + {.workDuration = notCloseOffset, .readyDuration = 0, .earliestVsync = 2000}); advanceToNextCallback(); ASSERT_THAT(cb1.mCalls.size(), Eq(2)); EXPECT_THAT(cb1.mCalls[1], Eq(2000)); @@ -446,8 +479,8 @@ TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenEndingAndDoesntCancel) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch.schedule(cb0, 100, 1000); - mDispatch.schedule(cb1, 200, 1000); + mDispatch.schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000}); advanceToNextCallback(); EXPECT_EQ(mDispatch.cancel(cb0), CancelResult::Cancelled); } @@ -460,18 +493,18 @@ TEST_F(VSyncDispatchTimerQueueTest, setAlarmCallsAtCorrectTimeWithChangingVsync) .WillOnce(Return(2950)); CountingCallback cb(mDispatch); - mDispatch.schedule(cb, 100, 920); + mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 920}); mMockClock.advanceBy(850); EXPECT_THAT(cb.mCalls.size(), Eq(1)); - mDispatch.schedule(cb, 100, 1900); + mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1900}); mMockClock.advanceBy(900); EXPECT_THAT(cb.mCalls.size(), Eq(1)); mMockClock.advanceBy(125); EXPECT_THAT(cb.mCalls.size(), Eq(2)); - mDispatch.schedule(cb, 100, 2900); + mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2900}); mMockClock.advanceBy(975); EXPECT_THAT(cb.mCalls.size(), Eq(3)); } @@ -482,10 +515,16 @@ TEST_F(VSyncDispatchTimerQueueTest, callbackReentrancy) { EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq); VSyncDispatch::CallbackToken tmp; - tmp = mDispatch.registerCallback([&](auto, auto) { mDispatch.schedule(tmp, 100, 2000); }, - "o.o"); + tmp = mDispatch.registerCallback( + [&](auto, auto, auto) { + mDispatch.schedule(tmp, + {.workDuration = 100, + .readyDuration = 0, + .earliestVsync = 2000}); + }, + "o.o"); - mDispatch.schedule(tmp, 100, 1000); + mDispatch.schedule(tmp, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); advanceToNextCallback(); } @@ -493,17 +532,27 @@ TEST_F(VSyncDispatchTimerQueueTest, callbackReentrantWithPastWakeup) { VSyncDispatch::CallbackToken tmp; std::optional lastTarget; tmp = mDispatch.registerCallback( - [&](auto timestamp, auto) { - EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp - mVsyncMoveThreshold), + [&](auto timestamp, auto, auto) { + EXPECT_EQ(mDispatch.schedule(tmp, + {.workDuration = 400, + .readyDuration = 0, + .earliestVsync = timestamp - mVsyncMoveThreshold}), + ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(tmp, + {.workDuration = 400, + .readyDuration = 0, + .earliestVsync = timestamp}), ScheduleResult::Scheduled); - EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp), ScheduleResult::Scheduled); - EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp + mVsyncMoveThreshold), + EXPECT_EQ(mDispatch.schedule(tmp, + {.workDuration = 400, + .readyDuration = 0, + .earliestVsync = timestamp + mVsyncMoveThreshold}), ScheduleResult::Scheduled); lastTarget = timestamp; }, "oo"); - mDispatch.schedule(tmp, 999, 1000); + mDispatch.schedule(tmp, {.workDuration = 999, .readyDuration = 0, .earliestVsync = 1000}); advanceToNextCallback(); EXPECT_THAT(lastTarget, Eq(1000)); @@ -519,16 +568,16 @@ TEST_F(VSyncDispatchTimerQueueTest, modificationsAroundVsyncTime) { EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq); CountingCallback cb(mDispatch); - mDispatch.schedule(cb, 0, 1000); + mDispatch.schedule(cb, {.workDuration = 0, .readyDuration = 0, .earliestVsync = 1000}); mMockClock.advanceBy(750); - mDispatch.schedule(cb, 50, 1000); + mDispatch.schedule(cb, {.workDuration = 50, .readyDuration = 0, .earliestVsync = 1000}); advanceToNextCallback(); - mDispatch.schedule(cb, 50, 2000); + mDispatch.schedule(cb, {.workDuration = 50, .readyDuration = 0, .earliestVsync = 2000}); mMockClock.advanceBy(800); - mDispatch.schedule(cb, 100, 2000); + mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}); } TEST_F(VSyncDispatchTimerQueueTest, lateModifications) { @@ -541,12 +590,12 @@ TEST_F(VSyncDispatchTimerQueueTest, lateModifications) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch.schedule(cb0, 500, 1000); - mDispatch.schedule(cb1, 100, 1000); + mDispatch.schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch.schedule(cb1, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); advanceToNextCallback(); - mDispatch.schedule(cb0, 200, 2000); - mDispatch.schedule(cb1, 150, 1000); + mDispatch.schedule(cb0, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 2000}); + mDispatch.schedule(cb1, {.workDuration = 150, .readyDuration = 0, .earliestVsync = 1000}); advanceToNextCallback(); advanceToNextCallback(); @@ -558,8 +607,8 @@ TEST_F(VSyncDispatchTimerQueueTest, doesntCancelPriorValidTimerForFutureMod) { CountingCallback cb0(mDispatch); CountingCallback cb1(mDispatch); - mDispatch.schedule(cb0, 500, 1000); - mDispatch.schedule(cb1, 500, 20000); + mDispatch.schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch.schedule(cb1, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 20000}); } TEST_F(VSyncDispatchTimerQueueTest, setsTimerAfterCancellation) { @@ -569,31 +618,43 @@ TEST_F(VSyncDispatchTimerQueueTest, setsTimerAfterCancellation) { EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq); CountingCallback cb0(mDispatch); - mDispatch.schedule(cb0, 500, 1000); + mDispatch.schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); mDispatch.cancel(cb0); - mDispatch.schedule(cb0, 100, 1000); + mDispatch.schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); } TEST_F(VSyncDispatchTimerQueueTest, makingUpIdsError) { VSyncDispatch::CallbackToken token(100); - EXPECT_THAT(mDispatch.schedule(token, 100, 1000), Eq(ScheduleResult::Error)); + EXPECT_THAT(mDispatch.schedule(token, + {.workDuration = 100, + .readyDuration = 0, + .earliestVsync = 1000}), + Eq(ScheduleResult::Error)); EXPECT_THAT(mDispatch.cancel(token), Eq(CancelResult::Error)); } TEST_F(VSyncDispatchTimerQueueTest, canMoveCallbackBackwardsInTime) { CountingCallback cb0(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled); - EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb0, + {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb0, + {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); } // b/1450138150 TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync) { EXPECT_CALL(mMockClock, alarmAt(_, 500)); CountingCallback cb(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); mMockClock.advanceBy(400); - EXPECT_EQ(mDispatch.schedule(cb, 800, 1000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 800, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); advanceToNextCallback(); ASSERT_THAT(cb.mCalls.size(), Eq(1)); } @@ -604,16 +665,24 @@ TEST_F(VSyncDispatchTimerQueueTest, targetOffsetMovingBackALittleCanStillSchedul .WillOnce(Return(1000)) .WillOnce(Return(1002)); CountingCallback cb(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); mMockClock.advanceBy(400); - EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); } TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) { CountingCallback cb0(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb0, + {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); advanceToNextCallback(); - EXPECT_EQ(mDispatch.schedule(cb0, 1100, 2000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb0, + {.workDuration = 1100, .readyDuration = 0, .earliestVsync = 2000}), + ScheduleResult::Scheduled); } TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) { @@ -621,18 +690,26 @@ TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) { EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq); EXPECT_CALL(mMockClock, alarmAt(_, 1100)).InSequence(seq); CountingCallback cb0(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb0, + {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); advanceToNextCallback(); - EXPECT_EQ(mDispatch.schedule(cb0, 1900, 2000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb0, + {.workDuration = 1900, .readyDuration = 0, .earliestVsync = 2000}), + ScheduleResult::Scheduled); } TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) { EXPECT_CALL(mMockClock, alarmAt(_, 600)); CountingCallback cb(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); - EXPECT_EQ(mDispatch.schedule(cb, 1400, 1000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 1400, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); advanceToNextCallback(); } @@ -642,12 +719,12 @@ TEST_F(VSyncDispatchTimerQueueTest, helperMove) { EXPECT_CALL(mMockClock, alarmCancel()).Times(1); VSyncCallbackRegistration cb( - mDispatch, [](auto, auto) {}, ""); + mDispatch, [](auto, auto, auto) {}, ""); VSyncCallbackRegistration cb1(std::move(cb)); - cb.schedule(100, 1000); + cb.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); cb.cancel(); - cb1.schedule(500, 1000); + cb1.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); cb1.cancel(); } @@ -656,14 +733,14 @@ TEST_F(VSyncDispatchTimerQueueTest, helperMoveAssign) { EXPECT_CALL(mMockClock, alarmCancel()).Times(1); VSyncCallbackRegistration cb( - mDispatch, [](auto, auto) {}, ""); + mDispatch, [](auto, auto, auto) {}, ""); VSyncCallbackRegistration cb1( - mDispatch, [](auto, auto) {}, ""); + mDispatch, [](auto, auto, auto) {}, ""); cb1 = std::move(cb); - cb.schedule(100, 1000); + cb.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}); cb.cancel(); - cb1.schedule(500, 1000); + cb1.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); cb1.cancel(); } @@ -675,12 +752,16 @@ TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminent CountingCallback cb1(mDispatch); CountingCallback cb2(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb1, + {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); mMockClock.setLag(100); mMockClock.advanceBy(620); - EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb2, + {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}), + ScheduleResult::Scheduled); mMockClock.advanceBy(80); EXPECT_THAT(cb1.mCalls.size(), Eq(1)); @@ -696,12 +777,16 @@ TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminent EXPECT_CALL(mMockClock, alarmAt(_, 1630)).InSequence(seq); CountingCallback cb(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); mMockClock.setLag(100); mMockClock.advanceBy(620); - EXPECT_EQ(mDispatch.schedule(cb, 370, 2000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 370, .readyDuration = 0, .earliestVsync = 2000}), + ScheduleResult::Scheduled); mMockClock.advanceBy(80); EXPECT_THAT(cb.mCalls.size(), Eq(1)); @@ -715,8 +800,12 @@ TEST_F(VSyncDispatchTimerQueueTest, skipsRearmingWhenNotNextScheduled) { CountingCallback cb1(mDispatch); CountingCallback cb2(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled); - EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb1, + {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb2, + {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}), + ScheduleResult::Scheduled); mMockClock.setLag(100); mMockClock.advanceBy(620); @@ -737,8 +826,12 @@ TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenCancelledAndIsNextScheduled) { CountingCallback cb1(mDispatch); CountingCallback cb2(mDispatch); - EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled); - EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb1, + {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb2, + {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}), + ScheduleResult::Scheduled); mMockClock.setLag(100); mMockClock.advanceBy(620); @@ -766,16 +859,44 @@ TEST_F(VSyncDispatchTimerQueueTest, laggedTimerGroupsCallbacksWithinLag) { .InSequence(seq) .WillOnce(Return(1000)); - EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled); - EXPECT_EQ(mDispatch.schedule(cb2, 390, 1000), ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb1, + {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); + EXPECT_EQ(mDispatch.schedule(cb2, + {.workDuration = 390, .readyDuration = 0, .earliestVsync = 1000}), + ScheduleResult::Scheduled); mMockClock.setLag(100); mMockClock.advanceBy(700); ASSERT_THAT(cb1.mWakeupTime.size(), Eq(1)); EXPECT_THAT(cb1.mWakeupTime[0], Eq(600)); + ASSERT_THAT(cb1.mReadyTime.size(), Eq(1)); + EXPECT_THAT(cb1.mReadyTime[0], Eq(1000)); ASSERT_THAT(cb2.mWakeupTime.size(), Eq(1)); EXPECT_THAT(cb2.mWakeupTime[0], Eq(610)); + ASSERT_THAT(cb2.mReadyTime.size(), Eq(1)); + EXPECT_THAT(cb2.mReadyTime[0], Eq(1000)); +} + +TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithReadyDuration) { + auto intended = mPeriod - 230; + EXPECT_CALL(mMockClock, alarmAt(_, 900)); + + CountingCallback cb(mDispatch); + EXPECT_EQ(mDispatch.schedule(cb, + {.workDuration = 70, + .readyDuration = 30, + .earliestVsync = intended}), + ScheduleResult::Scheduled); + advanceToNextCallback(); + + ASSERT_THAT(cb.mCalls.size(), Eq(1)); + EXPECT_THAT(cb.mCalls[0], Eq(mPeriod)); + ASSERT_THAT(cb.mWakeupTime.size(), Eq(1)); + EXPECT_THAT(cb.mWakeupTime[0], 900); + ASSERT_THAT(cb.mReadyTime.size(), Eq(1)); + EXPECT_THAT(cb.mReadyTime[0], 970); } class VSyncDispatchTimerQueueEntryTest : public testing::Test { @@ -788,7 +909,7 @@ protected: TEST_F(VSyncDispatchTimerQueueEntryTest, stateAfterInitialization) { std::string name("basicname"); VSyncDispatchTimerQueueEntry entry( - name, [](auto, auto) {}, mVsyncMoveThreshold); + name, [](auto, auto, auto) {}, mVsyncMoveThreshold); EXPECT_THAT(entry.name(), Eq(name)); EXPECT_FALSE(entry.lastExecutedVsyncTarget()); EXPECT_FALSE(entry.wakeupTime()); @@ -796,10 +917,12 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, stateAfterInitialization) { TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) { VSyncDispatchTimerQueueEntry entry( - "test", [](auto, auto) {}, mVsyncMoveThreshold); + "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); EXPECT_FALSE(entry.wakeupTime()); - EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); auto const wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(*wakeup, Eq(900)); @@ -816,10 +939,12 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, stateSchedulingReallyLongWakeupLatency) .Times(1) .WillOnce(Return(10000)); VSyncDispatchTimerQueueEntry entry( - "test", [](auto, auto) {}, mVsyncMoveThreshold); + "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); EXPECT_FALSE(entry.wakeupTime()); - EXPECT_THAT(entry.schedule(500, 994, mStubTracker, now), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 994}, + mStubTracker, now), + Eq(ScheduleResult::Scheduled)); auto const wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(*wakeup, Eq(9500)); @@ -829,21 +954,29 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) { auto callCount = 0; auto vsyncCalledTime = 0; auto wakeupCalledTime = 0; + auto readyCalledTime = 0; VSyncDispatchTimerQueueEntry entry( "test", - [&](auto vsyncTime, auto wakeupTime) { + [&](auto vsyncTime, auto wakeupTime, auto readyTime) { callCount++; vsyncCalledTime = vsyncTime; wakeupCalledTime = wakeupTime; + readyCalledTime = readyTime; }, mVsyncMoveThreshold); - EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); auto const wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(*wakeup, Eq(900)); - entry.callback(entry.executing(), *wakeup); + auto const ready = entry.readyTime(); + ASSERT_TRUE(ready); + EXPECT_THAT(*ready, Eq(1000)); + + entry.callback(entry.executing(), *wakeup, *ready); EXPECT_THAT(callCount, Eq(1)); EXPECT_THAT(vsyncCalledTime, Eq(mPeriod)); @@ -861,13 +994,15 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) { .WillOnce(Return(1020)); VSyncDispatchTimerQueueEntry entry( - "test", [](auto, auto) {}, mVsyncMoveThreshold); + "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); EXPECT_FALSE(entry.wakeupTime()); entry.update(mStubTracker, 0); EXPECT_FALSE(entry.wakeupTime()); - EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); auto wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(wakeup, Eq(900)); @@ -880,8 +1015,10 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) { TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) { VSyncDispatchTimerQueueEntry entry( - "test", [](auto, auto) {}, mVsyncMoveThreshold); - EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); + EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); entry.update(mStubTracker, 0); auto const wakeup = entry.wakeupTime(); @@ -891,24 +1028,35 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) { TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) { VSyncDispatchTimerQueueEntry entry( - "test", [](auto, auto) {}, mVsyncMoveThreshold); - EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); + EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); entry.executing(); // 1000 is executing // had 1000 not been executing, this could have been scheduled for time 800. - EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); EXPECT_THAT(*entry.wakeupTime(), Eq(1800)); + EXPECT_THAT(*entry.readyTime(), Eq(2000)); - EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule({.workDuration = 50, .readyDuration = 0, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); EXPECT_THAT(*entry.wakeupTime(), Eq(1950)); + EXPECT_THAT(*entry.readyTime(), Eq(2000)); - EXPECT_THAT(entry.schedule(200, 1001, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 1001}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); EXPECT_THAT(*entry.wakeupTime(), Eq(1800)); + EXPECT_THAT(*entry.readyTime(), Eq(2000)); } TEST_F(VSyncDispatchTimerQueueEntryTest, willRequestNextEstimateWhenSnappingToNextTargettableVSync) { VSyncDispatchTimerQueueEntry entry( - "test", [](auto, auto) {}, mVsyncMoveThreshold); + "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); Sequence seq; EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500)) @@ -921,35 +1069,85 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, .InSequence(seq) .WillOnce(Return(2000)); - EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); entry.executing(); // 1000 is executing - EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); } TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) { VSyncDispatchTimerQueueEntry entry( - "test", [](auto, auto) {}, mVsyncMoveThreshold); - EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); - EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); - EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); - EXPECT_THAT(entry.schedule(1200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); + "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); + EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule({.workDuration = 50, .readyDuration = 0, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); + EXPECT_THAT(entry.schedule({.workDuration = 1200, .readyDuration = 0, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); } TEST_F(VSyncDispatchTimerQueueEntryTest, storesPendingUpdatesUntilUpdate) { static constexpr auto effectualOffset = 200; VSyncDispatchTimerQueueEntry entry( - "test", [](auto, auto) {}, mVsyncMoveThreshold); + "test", [](auto, auto, auto) {}, mVsyncMoveThreshold); EXPECT_FALSE(entry.hasPendingWorkloadUpdate()); - entry.addPendingWorkloadUpdate(100, 400); - entry.addPendingWorkloadUpdate(effectualOffset, 700); + entry.addPendingWorkloadUpdate({.workDuration = 100, .readyDuration = 0, .earliestVsync = 400}); + entry.addPendingWorkloadUpdate( + {.workDuration = effectualOffset, .readyDuration = 0, .earliestVsync = 400}); EXPECT_TRUE(entry.hasPendingWorkloadUpdate()); entry.update(mStubTracker, 0); EXPECT_FALSE(entry.hasPendingWorkloadUpdate()); EXPECT_THAT(*entry.wakeupTime(), Eq(mPeriod - effectualOffset)); } +TEST_F(VSyncDispatchTimerQueueEntryTest, runCallbackWithReadyDuration) { + auto callCount = 0; + auto vsyncCalledTime = 0; + auto wakeupCalledTime = 0; + auto readyCalledTime = 0; + VSyncDispatchTimerQueueEntry entry( + "test", + [&](auto vsyncTime, auto wakeupTime, auto readyTime) { + callCount++; + vsyncCalledTime = vsyncTime; + wakeupCalledTime = wakeupTime; + readyCalledTime = readyTime; + }, + mVsyncMoveThreshold); + + EXPECT_THAT(entry.schedule({.workDuration = 70, .readyDuration = 30, .earliestVsync = 500}, + mStubTracker, 0), + Eq(ScheduleResult::Scheduled)); + auto const wakeup = entry.wakeupTime(); + ASSERT_TRUE(wakeup); + EXPECT_THAT(*wakeup, Eq(900)); + + auto const ready = entry.readyTime(); + ASSERT_TRUE(ready); + EXPECT_THAT(*ready, Eq(970)); + + entry.callback(entry.executing(), *wakeup, *ready); + + EXPECT_THAT(callCount, Eq(1)); + EXPECT_THAT(vsyncCalledTime, Eq(mPeriod)); + EXPECT_THAT(wakeupCalledTime, Eq(*wakeup)); + EXPECT_FALSE(entry.wakeupTime()); + auto lastCalledTarget = entry.lastExecutedVsyncTarget(); + ASSERT_TRUE(lastCalledTarget); + EXPECT_THAT(*lastCalledTarget, Eq(mPeriod)); +} + } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index c5cddf3fba..0c1ae14d41 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -63,9 +63,9 @@ private: class MockVSyncDispatch : public VSyncDispatch { public: MOCK_METHOD2(registerCallback, - CallbackToken(std::function const&, std::string)); + CallbackToken(std::function const&, std::string)); MOCK_METHOD1(unregisterCallback, void(CallbackToken)); - MOCK_METHOD3(schedule, ScheduleResult(CallbackToken, nsecs_t, nsecs_t)); + MOCK_METHOD2(schedule, ScheduleResult(CallbackToken, ScheduleTiming)); MOCK_METHOD1(cancel, CancelResult(CallbackToken token)); MOCK_CONST_METHOD1(dump, void(std::string&)); }; @@ -92,22 +92,6 @@ std::shared_ptr generateSignalledFenceWithTime(nsecs_t time) { return ft; } -class StubCallback : public DispSync::Callback { -public: - void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final { - std::lock_guard lk(mMutex); - mLastCallTime = when; - } - std::optional lastCallTime() const { - std::lock_guard lk(mMutex); - return mLastCallTime; - } - -private: - std::mutex mutable mMutex; - std::optional mLastCallTime GUARDED_BY(mMutex); -}; - class VSyncReactorTest : public testing::Test { protected: VSyncReactorTest() @@ -135,7 +119,7 @@ protected: VSyncDispatch::CallbackToken const mFakeToken{2398}; nsecs_t lastCallbackTime = 0; - StubCallback outerCb; + // StubCallback outerCb; std::function innerCb; VSyncReactor mReactor; @@ -489,192 +473,6 @@ TEST_F(VSyncReactorTest, hwVsyncIsRequestedForTrackerMultiplePeriodChanges) { EXPECT_FALSE(mReactor.addResyncSample(time += newPeriod2, std::nullopt, &periodFlushed)); } -static nsecs_t computeWorkload(nsecs_t period, nsecs_t phase) { - return period - phase; -} - -TEST_F(VSyncReactorTest, addEventListener) { - Sequence seq; - EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) - .InSequence(seq) - .WillOnce(Return(mFakeToken)); - EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) - .InSequence(seq); - EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq); - EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq); - - mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); - mReactor.removeEventListener(&outerCb, &lastCallbackTime); -} - -TEST_F(VSyncReactorTest, addEventListenerTwiceChangesPhase) { - Sequence seq; - EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) - .InSequence(seq) - .WillOnce(Return(mFakeToken)); - EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) - .InSequence(seq); - EXPECT_CALL(*mMockDispatch, - schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _)) // mFakeNow)) - .InSequence(seq); - EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq); - EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq); - - mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); - mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime); -} - -TEST_F(VSyncReactorTest, eventListenerGetsACallbackAndReschedules) { - Sequence seq; - EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) - .InSequence(seq) - .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken))); - EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) - .InSequence(seq); - EXPECT_CALL(*mMockDispatch, - schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime)) - .Times(2) - .InSequence(seq); - EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq); - EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq); - - mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); - ASSERT_TRUE(innerCb); - innerCb(mFakeVSyncTime, mFakeWakeupTime); - innerCb(mFakeVSyncTime, mFakeWakeupTime); -} - -TEST_F(VSyncReactorTest, callbackTimestampDistributedIsWakeupTime) { - Sequence seq; - EXPECT_CALL(*mMockDispatch, registerCallback(_, _)) - .InSequence(seq) - .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken))); - EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) - .InSequence(seq); - EXPECT_CALL(*mMockDispatch, - schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime)) - .InSequence(seq); - - mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); - ASSERT_TRUE(innerCb); - innerCb(mFakeVSyncTime, mFakeWakeupTime); - EXPECT_THAT(outerCb.lastCallTime(), Optional(mFakeWakeupTime)); -} - -TEST_F(VSyncReactorTest, eventListenersRemovedOnDestruction) { - Sequence seq; - EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) - .InSequence(seq) - .WillOnce(Return(mFakeToken)); - EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) - .InSequence(seq); - EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq); - EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq); - - mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); -} - -// b/149221293 -TEST_F(VSyncReactorTest, selfRemovingEventListenerStopsCallbacks) { - class SelfRemovingCallback : public DispSync::Callback { - public: - SelfRemovingCallback(VSyncReactor& vsr) : mVsr(vsr) {} - void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final { - mVsr.removeEventListener(this, &when); - } - - private: - VSyncReactor& mVsr; - } selfRemover(mReactor); - - Sequence seq; - EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) - .InSequence(seq) - .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken))); - EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) - .InSequence(seq); - EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq); - EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq); - - mReactor.addEventListener(mName, mPhase, &selfRemover, lastCallbackTime); - innerCb(0, 0); -} - -TEST_F(VSyncReactorTest, addEventListenerChangePeriod) { - Sequence seq; - EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) - .InSequence(seq) - .WillOnce(Return(mFakeToken)); - EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) - .InSequence(seq); - EXPECT_CALL(*mMockDispatch, - schedule(mFakeToken, computeWorkload(period, mAnotherPhase), mFakeNow)) - .InSequence(seq); - EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq); - EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq); - - mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); - mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime); -} - -TEST_F(VSyncReactorTest, changingPeriodChangesOffsetsOnNextCb) { - static constexpr nsecs_t anotherPeriod = 23333; - Sequence seq; - EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) - .InSequence(seq) - .WillOnce(Return(mFakeToken)); - EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow)) - .InSequence(seq); - EXPECT_CALL(*mMockTracker, setPeriod(anotherPeriod)); - EXPECT_CALL(*mMockDispatch, - schedule(mFakeToken, computeWorkload(anotherPeriod, mPhase), mFakeNow)) - .InSequence(seq); - - mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); - - bool periodFlushed = false; - mReactor.setPeriod(anotherPeriod); - EXPECT_TRUE(mReactor.addResyncSample(anotherPeriod, std::nullopt, &periodFlushed)); - EXPECT_FALSE(mReactor.addResyncSample(anotherPeriod * 2, std::nullopt, &periodFlushed)); - - mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); -} - -TEST_F(VSyncReactorTest, offsetsAppliedOnNextOpportunity) { - Sequence seq; - EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) - .InSequence(seq) - .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken))); - EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), _)) - .InSequence(seq) - .WillOnce(Return(ScheduleResult::Scheduled)); - - EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _)) - .InSequence(seq) - .WillOnce(Return(ScheduleResult::Scheduled)); - - EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _)) - .InSequence(seq) - .WillOnce(Return(ScheduleResult::Scheduled)); - - mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); - mReactor.changePhaseOffset(&outerCb, mAnotherPhase); - ASSERT_TRUE(innerCb); - innerCb(mFakeVSyncTime, mFakeWakeupTime); -} - -TEST_F(VSyncReactorTest, negativeOffsetsApplied) { - nsecs_t const negativePhase = -4000; - Sequence seq; - EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) - .InSequence(seq) - .WillOnce(Return(mFakeToken)); - EXPECT_CALL(*mMockDispatch, - schedule(mFakeToken, computeWorkload(period, negativePhase), mFakeNow)) - .InSequence(seq); - mReactor.addEventListener(mName, negativePhase, &outerCb, lastCallbackTime); -} - TEST_F(VSyncReactorTest, beginResyncResetsModel) { EXPECT_CALL(*mMockTracker, resetModel()); mReactor.beginResync(); @@ -734,42 +532,4 @@ TEST_F(VSyncReactorTest, periodIsMeasuredIfIgnoringComposer) { EXPECT_TRUE(idleReactor.addPresentFence(generateSignalledFenceWithTime(0))); } -using VSyncReactorDeathTest = VSyncReactorTest; -TEST_F(VSyncReactorDeathTest, invalidRemoval) { - mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); - mReactor.removeEventListener(&outerCb, &lastCallbackTime); - EXPECT_DEATH(mReactor.removeEventListener(&outerCb, &lastCallbackTime), ".*"); -} - -TEST_F(VSyncReactorDeathTest, invalidChange) { - EXPECT_DEATH(mReactor.changePhaseOffset(&outerCb, mPhase), ".*"); - - // the current DispSync-interface usage pattern has evolved around an implementation quirk, - // which is a callback is assumed to always exist, and it is valid api usage to change the - // offset of an object that is in the removed state. - mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); - mReactor.removeEventListener(&outerCb, &lastCallbackTime); - mReactor.changePhaseOffset(&outerCb, mPhase); -} - -TEST_F(VSyncReactorDeathTest, cannotScheduleOnRegistration) { - ON_CALL(*mMockDispatch, schedule(_, _, _)) - .WillByDefault(Return(ScheduleResult::CannotSchedule)); - EXPECT_DEATH(mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime), ".*"); -} - -TEST_F(VSyncReactorDeathTest, cannotScheduleOnCallback) { - EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName))) - .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken))); - EXPECT_CALL(*mMockDispatch, schedule(_, _, _)).WillOnce(Return(ScheduleResult::Scheduled)); - - mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime); - ASSERT_TRUE(innerCb); - Mock::VerifyAndClearExpectations(mMockDispatch.get()); - - ON_CALL(*mMockDispatch, schedule(_, _, _)) - .WillByDefault(Return(ScheduleResult::CannotSchedule)); - EXPECT_DEATH(innerCb(mFakeVSyncTime, mFakeWakeupTime), ".*"); -} - } // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp index 1c8c44dca0..bbd9f770f6 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp +++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp @@ -25,40 +25,5 @@ namespace mock { DispSync::DispSync() = default; DispSync::~DispSync() = default; -status_t DispSync::addEventListener(const char* /*name*/, nsecs_t phase, Callback* callback, - nsecs_t /*lastCallbackTime*/) { - if (mCallback.callback != nullptr) { - return BAD_VALUE; - } - - mCallback = {callback, phase}; - return NO_ERROR; -} -status_t DispSync::removeEventListener(Callback* callback, nsecs_t* /*outLastCallback*/) { - if (mCallback.callback != callback) { - return BAD_VALUE; - } - - mCallback = {nullptr, 0}; - return NO_ERROR; -} - -status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) { - if (mCallback.callback != callback) { - return BAD_VALUE; - } - - mCallback.phase = phase; - return NO_ERROR; -} - -void DispSync::triggerCallback() { - if (mCallback.callback == nullptr) return; - - const std::chrono::nanoseconds now = std::chrono::steady_clock::now().time_since_epoch(); - const auto expectedVSyncTime = now + 16ms; - mCallback.callback->onDispSyncEvent(now.count(), expectedVSyncTime.count()); -} - } // namespace mock } // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h index b39487ccc1..41445c8ae6 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h +++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h @@ -28,11 +28,9 @@ public: DispSync(); ~DispSync() override; - MOCK_METHOD0(reset, void()); MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr&)); MOCK_METHOD0(beginResync, void()); MOCK_METHOD3(addResyncSample, bool(nsecs_t, std::optional, bool*)); - MOCK_METHOD0(endResync, void()); MOCK_METHOD1(setPeriod, void(nsecs_t)); MOCK_METHOD0(getPeriod, nsecs_t()); MOCK_METHOD0(getIntendedPeriod, nsecs_t()); @@ -42,22 +40,6 @@ public: MOCK_METHOD1(expectedPresentTime, nsecs_t(nsecs_t)); MOCK_CONST_METHOD1(dump, void(std::string&)); - - status_t addEventListener(const char* name, nsecs_t phase, Callback* callback, - nsecs_t lastCallbackTime) override; - status_t removeEventListener(Callback* callback, nsecs_t* outLastCallback) override; - status_t changePhaseOffset(Callback* callback, nsecs_t phase) override; - - nsecs_t getCallbackPhase() { return mCallback.phase; } - - void triggerCallback(); - -private: - struct CallbackType { - Callback* callback = nullptr; - nsecs_t phase; - }; - CallbackType mCallback; }; } // namespace mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 054aaf8ae1..eefdec18aa 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -35,7 +35,9 @@ public: MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool)); MOCK_METHOD3(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType, nsecs_t)); MOCK_CONST_METHOD1(dump, void(std::string&)); - MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset)); + MOCK_METHOD2(setDuration, + void(std::chrono::nanoseconds workDuration, + std::chrono::nanoseconds readyDuration)); MOCK_METHOD1(registerDisplayEventConnection, status_t(const sp &)); MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp &)); -- cgit v1.2.3-59-g8ed1b From 8cb2188b3b5b923f0a4ae2bdb73ea85c2ae00820 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 26 Aug 2020 18:22:05 -0700 Subject: SurfaceFlinger: DispSync -> VsyncController Refactor the old DispSync to separate between Vsync math (VsyncTracker) and fence / vsync callback management (VsyncController) Bug: 162888874 Test: examine systraces Test: SF unit tests Change-Id: Id275620380a21aeb0017e966910cbf24860cecef --- libs/gui/include/gui/DisplayEventReceiver.h | 1 + services/surfaceflinger/BufferLayerConsumer.cpp | 2 +- services/surfaceflinger/BufferLayerConsumer.h | 1 - services/surfaceflinger/RegionSamplingThread.cpp | 4 +- services/surfaceflinger/Scheduler/DispSync.h | 55 ------ .../surfaceflinger/Scheduler/DispSyncSource.cpp | 5 +- services/surfaceflinger/Scheduler/EventThread.cpp | 14 +- services/surfaceflinger/Scheduler/Scheduler.cpp | 46 ++--- services/surfaceflinger/Scheduler/Scheduler.h | 17 +- services/surfaceflinger/Scheduler/Timer.cpp | 10 +- .../Scheduler/VSyncDispatchTimerQueue.cpp | 14 +- services/surfaceflinger/Scheduler/VSyncReactor.cpp | 47 ++--- services/surfaceflinger/Scheduler/VSyncReactor.h | 26 ++- .../surfaceflinger/Scheduler/VsyncController.h | 85 +++++++++ services/surfaceflinger/SurfaceFlinger.cpp | 23 ++- services/surfaceflinger/SurfaceFlinger.h | 2 +- .../SurfaceFlingerDefaultFactory.cpp | 2 +- services/surfaceflinger/SurfaceFlingerFactory.h | 2 +- services/surfaceflinger/tests/unittests/Android.bp | 5 +- .../tests/unittests/CompositionTest.cpp | 16 +- .../tests/unittests/DisplayTransactionTest.cpp | 25 +-- .../tests/unittests/RefreshRateSelectionTest.cpp | 26 ++- .../tests/unittests/SetFrameRateTest.cpp | 15 +- .../tests/unittests/TestableScheduler.h | 17 +- .../tests/unittests/TestableSurfaceFlinger.h | 9 +- .../tests/unittests/TransactionApplicationTest.cpp | 20 ++- .../tests/unittests/VSyncDispatchRealtimeTest.cpp | 18 +- .../unittests/VSyncDispatchTimerQueueTest.cpp | 10 +- .../tests/unittests/VSyncReactorTest.cpp | 192 ++++++++------------- .../tests/unittests/mock/MockDispSync.cpp | 29 ---- .../tests/unittests/mock/MockDispSync.h | 46 ----- .../tests/unittests/mock/MockVSyncTracker.cpp | 29 ++++ .../tests/unittests/mock/MockVSyncTracker.h | 39 +++++ .../tests/unittests/mock/MockVsyncController.cpp | 27 +++ .../tests/unittests/mock/MockVsyncController.h | 40 +++++ 35 files changed, 471 insertions(+), 448 deletions(-) delete mode 100644 services/surfaceflinger/Scheduler/DispSync.h create mode 100644 services/surfaceflinger/Scheduler/VsyncController.h delete mode 100644 services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp delete mode 100644 services/surfaceflinger/tests/unittests/mock/MockDispSync.h create mode 100644 services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.cpp create mode 100644 services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h create mode 100644 services/surfaceflinger/tests/unittests/mock/MockVsyncController.cpp create mode 100644 services/surfaceflinger/tests/unittests/mock/MockVsyncController.h (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 7974a0648c..0d0d10289c 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -72,6 +72,7 @@ public: struct VSync { uint32_t count; nsecs_t expectedVSyncTimestamp __attribute__((aligned(8))); + nsecs_t deadlineTimestamp __attribute__((aligned(8))); }; struct Hotplug { diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 8722952bba..94cbfa1803 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -25,7 +25,7 @@ #include "BufferLayerConsumer.h" #include "Layer.h" -#include "Scheduler/DispSync.h" +#include "Scheduler/VsyncController.h" #include diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index 5e3044fd98..a28902d964 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -34,7 +34,6 @@ namespace android { // ---------------------------------------------------------------------------- -class DispSync; class Layer; class String8; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index b24855d77c..6ba1942e2b 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -38,7 +38,7 @@ #include "DisplayRenderArea.h" #include "Layer.h" #include "Promise.h" -#include "Scheduler/DispSync.h" +#include "Scheduler/VsyncController.h" #include "SurfaceFlinger.h" namespace android { @@ -249,7 +249,7 @@ void RegionSamplingThread::doSample() { // until the next vsync deadline, defer this sampling work // to a later frame, when hopefully there will be more time. DisplayStatInfo stats; - mScheduler.getDisplayStatInfo(&stats); + mScheduler.getDisplayStatInfo(&stats, systemTime()); if (std::chrono::nanoseconds(stats.vsyncTime) - now < timeForRegionSampling) { ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::waitForQuietFrame)); mDiscardedFrames++; diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h deleted file mode 100644 index f34aabce19..0000000000 --- a/services/surfaceflinger/Scheduler/DispSync.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2012 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 - -#include -#include -#include - -#include - -#include - -namespace android { - -class FenceTime; - -class DispSync { -public: - DispSync() = default; - virtual ~DispSync() = default; - - virtual bool addPresentFence(const std::shared_ptr&) = 0; - virtual void beginResync() = 0; - virtual bool addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, - bool* periodFlushed) = 0; - virtual void setPeriod(nsecs_t period) = 0; - virtual nsecs_t getPeriod() = 0; - virtual nsecs_t computeNextRefresh(int periodOffset, nsecs_t now) const = 0; - virtual void setIgnorePresentFences(bool ignore) = 0; - virtual nsecs_t expectedPresentTime(nsecs_t now) = 0; - - virtual void dump(std::string& result) const = 0; - -protected: - DispSync(DispSync const&) = delete; - DispSync& operator=(DispSync const&) = delete; -}; - -} // namespace android diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 75f072dcd4..ce5c31ac19 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -22,16 +22,13 @@ #include #include -#include "DispSync.h" #include "EventThread.h" +#include "VsyncController.h" namespace android::scheduler { using base::StringAppendF; using namespace std::chrono_literals; -// The DispSync interface has a 'repeat this callback at rate' semantic. This object adapts -// VSyncDispatch's individually-scheduled callbacks so as to meet DispSync's existing semantic -// for now. class CallbackRepeater { public: CallbackRepeater(VSyncDispatch& dispatch, VSyncDispatch::Callback cb, const char* name, diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 559626b24f..f513535658 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -98,11 +98,13 @@ DisplayEventReceiver::Event makeHotplug(PhysicalDisplayId displayId, nsecs_t tim } DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp, - uint32_t count, nsecs_t expectedVSyncTimestamp) { + uint32_t count, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) { DisplayEventReceiver::Event event; event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp}; event.vsync.count = count; event.vsync.expectedVSyncTimestamp = expectedVSyncTimestamp; + event.vsync.deadlineTimestamp = deadlineTimestamp; return event; } @@ -285,12 +287,12 @@ void EventThread::onScreenAcquired() { } void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, - nsecs_t /*deadlineTimestamp*/) { + nsecs_t deadlineTimestamp) { std::lock_guard lock(mMutex); LOG_FATAL_IF(!mVSyncState); mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count, - expectedVSyncTimestamp)); + expectedVSyncTimestamp, deadlineTimestamp)); mCondition.notify_all(); } @@ -412,9 +414,11 @@ void EventThread::threadMain(std::unique_lock& lock) { LOG_FATAL_IF(!mVSyncState); const auto now = systemTime(SYSTEM_TIME_MONOTONIC); - const auto expectedVSyncTime = now + timeout.count(); + const auto deadlineTimestamp = now + timeout.count(); + const auto expectedVSyncTime = deadlineTimestamp + timeout.count(); mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now, - ++mVSyncState->count, expectedVSyncTime)); + ++mVSyncState->count, expectedVSyncTime, + deadlineTimestamp)); } } } diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index b0b5e2eff1..5271ccc704 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -39,7 +39,6 @@ #include #include "../Layer.h" -#include "DispSync.h" #include "DispSyncSource.h" #include "EventThread.h" #include "InjectVSyncSource.h" @@ -50,6 +49,7 @@ #include "VSyncDispatchTimerQueue.h" #include "VSyncPredictor.h" #include "VSyncReactor.h" +#include "VsyncController.h" #define RETURN_IF_INVALID_HANDLE(handle, ...) \ do { \ @@ -124,7 +124,7 @@ Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCal Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback, Options options) - : Scheduler(createVsyncSchedule(options), configs, callback, + : Scheduler(createVsyncSchedule(options.supportKernelTimer), configs, callback, createLayerHistory(configs, options.useContentDetectionV2), options) { using namespace sysprop; @@ -180,17 +180,17 @@ Scheduler::~Scheduler() { mIdleTimer.reset(); } -Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(Options options) { +Scheduler::VsyncSchedule Scheduler::createVsyncSchedule(bool supportKernelTimer) { auto clock = std::make_unique(); auto tracker = createVSyncTracker(); auto dispatch = createVSyncDispatch(*tracker); // TODO(b/144707443): Tune constants. constexpr size_t pendingFenceLimit = 20; - auto sync = + auto controller = std::make_unique(std::move(clock), *tracker, pendingFenceLimit, - options.supportKernelTimer); - return {std::move(sync), std::move(tracker), std::move(dispatch)}; + supportKernelTimer); + return {std::move(controller), std::move(tracker), std::move(dispatch)}; } std::unique_ptr Scheduler::createLayerHistory( @@ -204,10 +204,6 @@ std::unique_ptr Scheduler::createLayerHistory( return std::make_unique(); } -DispSync& Scheduler::getPrimaryDispSync() { - return *mVsyncSchedule.sync; -} - std::unique_ptr Scheduler::makePrimaryDispSyncSource( const char* name, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, bool traceVsync) { @@ -318,9 +314,9 @@ void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds wo mConnections[handle].thread->setDuration(workDuration, readyDuration); } -void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) { - stats->vsyncTime = getPrimaryDispSync().computeNextRefresh(0, systemTime()); - stats->vsyncPeriod = getPrimaryDispSync().getPeriod(); +void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats, nsecs_t now) { + stats->vsyncTime = mVsyncSchedule.tracker->nextAnticipatedVSyncTimeFrom(now); + stats->vsyncPeriod = mVsyncSchedule.tracker->currentPeriod(); } Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { @@ -357,7 +353,7 @@ bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime, nsecs_t dea void Scheduler::enableHardwareVsync() { std::lock_guard lock(mHWVsyncLock); if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { - getPrimaryDispSync().beginResync(); + mVsyncSchedule.tracker->resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } @@ -406,10 +402,10 @@ void Scheduler::resync() { void Scheduler::setVsyncPeriod(nsecs_t period) { std::lock_guard lock(mHWVsyncLock); - getPrimaryDispSync().setPeriod(period); + mVsyncSchedule.controller->startPeriodTransition(period); if (!mPrimaryHWVsyncEnabled) { - getPrimaryDispSync().beginResync(); + mVsyncSchedule.tracker->resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } @@ -422,8 +418,8 @@ void Scheduler::addResyncSample(nsecs_t timestamp, std::optional hwcVsy { // Scope for the lock std::lock_guard lock(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { - needsHwVsync = - getPrimaryDispSync().addResyncSample(timestamp, hwcVsyncPeriod, periodFlushed); + needsHwVsync = mVsyncSchedule.controller->addHwVsyncTimestamp(timestamp, hwcVsyncPeriod, + periodFlushed); } } @@ -435,7 +431,7 @@ void Scheduler::addResyncSample(nsecs_t timestamp, std::optional hwcVsy } void Scheduler::addPresentFence(const std::shared_ptr& fenceTime) { - if (getPrimaryDispSync().addPresentFence(fenceTime)) { + if (mVsyncSchedule.controller->addPresentFence(fenceTime)) { enableHardwareVsync(); } else { disableHardwareVsync(false); @@ -443,11 +439,7 @@ void Scheduler::addPresentFence(const std::shared_ptr& fenceTime) { } void Scheduler::setIgnorePresentFences(bool ignore) { - getPrimaryDispSync().setIgnorePresentFences(ignore); -} - -nsecs_t Scheduler::getDispSyncExpectedPresentTime(nsecs_t now) { - return getPrimaryDispSync().expectedPresentTime(now); + mVsyncSchedule.controller->setIgnorePresentFences(ignore); } void Scheduler::registerLayer(Layer* layer) { @@ -581,7 +573,7 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { refreshRate.getFps() <= FPS_THRESHOLD_FOR_KERNEL_TIMER) { // Disable HW VSYNC if the timer expired, as we don't need it enabled if // we're not pushing frames, and if we're in PERFORMANCE mode then we'll - // need to update the DispSync model anyway. + // need to update the VsyncController model anyway. disableHardwareVsync(false /* makeUnavailable */); } @@ -624,11 +616,11 @@ void Scheduler::dump(std::string& result) const { mLayerHistory ? mLayerHistory->dump().c_str() : "(no layer history)"); } -void Scheduler::dumpVSync(std::string& s) const { +void Scheduler::dumpVsync(std::string& s) const { using base::StringAppendF; StringAppendF(&s, "VSyncReactor:\n"); - mVsyncSchedule.sync->dump(s); + mVsyncSchedule.controller->dump(s); StringAppendF(&s, "VSyncDispatch:\n"); mVsyncSchedule.dispatch->dump(s); } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 9a4ac369f3..0b5c9d2c3f 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -40,12 +40,12 @@ namespace android { using namespace std::chrono_literals; using scheduler::LayerHistory; -class DispSync; class FenceTime; class InjectVSyncSource; class PredictedVsyncTracer; namespace scheduler { +class VsyncController; class VSyncDispatch; class VSyncTracker; } // namespace scheduler @@ -69,8 +69,6 @@ public: Scheduler(const scheduler::RefreshRateConfigs&, ISchedulerCallback&); ~Scheduler(); - DispSync& getPrimaryDispSync(); - using ConnectionHandle = scheduler::ConnectionHandle; ConnectionHandle createConnection(const char* connectionName, std::chrono::nanoseconds workDuration, @@ -95,7 +93,7 @@ public: void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration); - void getDisplayStatInfo(DisplayStatInfo* stats); + void getDisplayStatInfo(DisplayStatInfo* stats, nsecs_t now); // Returns injector handle if injection has toggled, or an invalid handle otherwise. ConnectionHandle enableVSyncInjection(bool enable); @@ -112,13 +110,12 @@ public: void resyncToHardwareVsync(bool makeAvailable, nsecs_t period); void resync(); - // Passes a vsync sample to DispSync. periodFlushed will be true if - // DispSync detected that the vsync period changed, and false otherwise. + // Passes a vsync sample to VsyncController. periodFlushed will be true if + // VsyncController detected that the vsync period changed, and false otherwise. void addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, bool* periodFlushed); void addPresentFence(const std::shared_ptr&); void setIgnorePresentFences(bool ignore); - nsecs_t getDispSyncExpectedPresentTime(nsecs_t now); // Layers are registered on creation, and unregistered when the weak reference expires. void registerLayer(Layer*); @@ -138,7 +135,7 @@ public: void dump(std::string&) const; void dump(ConnectionHandle, std::string&) const; - void dumpVSync(std::string&) const; + void dumpVsync(std::string&) const; // Get the appropriate refresh for current conditions. std::optional getPreferredConfigId(); @@ -178,7 +175,7 @@ private: }; struct VsyncSchedule { - std::unique_ptr sync; + std::unique_ptr controller; std::unique_ptr tracker; std::unique_ptr dispatch; }; @@ -190,7 +187,7 @@ private: Scheduler(VsyncSchedule, const scheduler::RefreshRateConfigs&, ISchedulerCallback&, std::unique_ptr, Options); - static VsyncSchedule createVsyncSchedule(Options); + static VsyncSchedule createVsyncSchedule(bool supportKernelIdleTimer); static std::unique_ptr createLayerHistory(const scheduler::RefreshRateConfigs&, bool useContentDetectionV2); diff --git a/services/surfaceflinger/Scheduler/Timer.cpp b/services/surfaceflinger/Scheduler/Timer.cpp index 59c336ab10..c9c2d84a2a 100644 --- a/services/surfaceflinger/Scheduler/Timer.cpp +++ b/services/surfaceflinger/Scheduler/Timer.cpp @@ -89,7 +89,7 @@ nsecs_t Timer::now() const { } void Timer::alarmAt(std::function const& cb, nsecs_t time) { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); using namespace std::literals; static constexpr int ns_per_s = std::chrono::duration_cast(1s).count(); @@ -109,7 +109,7 @@ void Timer::alarmAt(std::function const& cb, nsecs_t time) { } void Timer::alarmCancel() { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); struct itimerspec old_timer; struct itimerspec new_timer { @@ -192,7 +192,7 @@ bool Timer::dispatch() { setDebugState(DebugState::Running); std::function cb; { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); cb = mCallback; } if (cb) { @@ -211,7 +211,7 @@ bool Timer::dispatch() { } void Timer::setDebugState(DebugState state) { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); mDebugState = state; } @@ -233,7 +233,7 @@ const char* Timer::strDebugState(DebugState state) const { } void Timer::dump(std::string& result) const { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); StringAppendF(&result, "\t\tDebugState: %s\n", strDebugState(mDebugState)); } diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp index 2154a40517..ca6ea27d14 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp @@ -185,7 +185,7 @@ VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr tk, mMinVsyncDistance(minVsyncDistance) {} VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); cancelTimer(); } @@ -257,7 +257,7 @@ void VSyncDispatchTimerQueue::timerCallback() { }; std::vector invocations; { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); auto const now = mTimeKeeper->now(); mLastTimerCallback = now; for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) { @@ -289,7 +289,7 @@ void VSyncDispatchTimerQueue::timerCallback() { VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback( Callback const& callbackFn, std::string callbackName) { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); return CallbackToken{ mCallbacks .emplace(++mCallbackToken, @@ -302,7 +302,7 @@ VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) { std::shared_ptr entry = nullptr; { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); auto it = mCallbacks.find(token); if (it != mCallbacks.end()) { entry = it->second; @@ -319,7 +319,7 @@ ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, ScheduleTiming scheduleTiming) { auto result = ScheduleResult::Error; { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); auto it = mCallbacks.find(token); if (it == mCallbacks.end()) { @@ -350,7 +350,7 @@ ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, } CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); auto it = mCallbacks.find(token); if (it == mCallbacks.end()) { @@ -372,7 +372,7 @@ CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) { } void VSyncDispatchTimerQueue::dump(std::string& result) const { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); StringAppendF(&result, "\tTimer:\n"); mTimeKeeper->dump(result); StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f, diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index 3c5b3f1ff5..7b5d4626dc 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -30,6 +30,8 @@ namespace android::scheduler { using base::StringAppendF; +VsyncController::~VsyncController() = default; + Clock::~Clock() = default; nsecs_t SystemClock::now() const { return systemTime(SYSTEM_TIME_MONOTONIC); @@ -44,7 +46,7 @@ VSyncReactor::VSyncReactor(std::unique_ptr clock, VSyncTracker& tracker, VSyncReactor::~VSyncReactor() = default; -bool VSyncReactor::addPresentFence(const std::shared_ptr& fence) { +bool VSyncReactor::addPresentFence(const std::shared_ptr& fence) { if (!fence) { return false; } @@ -91,14 +93,14 @@ bool VSyncReactor::addPresentFence(const std::shared_ptr& fence) { return mMoreSamplesNeeded; } -void VSyncReactor::setIgnorePresentFences(bool ignoration) { +void VSyncReactor::setIgnorePresentFences(bool ignore) { std::lock_guard lock(mMutex); - mExternalIgnoreFences = ignoration; + mExternalIgnoreFences = ignore; updateIgnorePresentFencesInternal(); } -void VSyncReactor::setIgnorePresentFencesInternal(bool ignoration) { - mInternalIgnoreFences = ignoration; +void VSyncReactor::setIgnorePresentFencesInternal(bool ignore) { + mInternalIgnoreFences = ignore; updateIgnorePresentFencesInternal(); } @@ -108,16 +110,7 @@ void VSyncReactor::updateIgnorePresentFencesInternal() { } } -nsecs_t VSyncReactor::computeNextRefresh(int periodOffset, nsecs_t now) const { - auto const currentPeriod = periodOffset ? mTracker.currentPeriod() : 0; - return mTracker.nextAnticipatedVSyncTimeFrom(now + periodOffset * currentPeriod); -} - -nsecs_t VSyncReactor::expectedPresentTime(nsecs_t now) { - return mTracker.nextAnticipatedVSyncTimeFrom(now); -} - -void VSyncReactor::startPeriodTransition(nsecs_t newPeriod) { +void VSyncReactor::startPeriodTransitionInternal(nsecs_t newPeriod) { ATRACE_CALL(); mPeriodConfirmationInProgress = true; mPeriodTransitioningTo = newPeriod; @@ -132,28 +125,20 @@ void VSyncReactor::endPeriodTransition() { mLastHwVsync.reset(); } -void VSyncReactor::setPeriod(nsecs_t period) { +void VSyncReactor::startPeriodTransition(nsecs_t period) { ATRACE_INT64("VSR-setPeriod", period); - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); mLastHwVsync.reset(); - if (!mSupportKernelIdleTimer && period == getPeriod()) { + if (!mSupportKernelIdleTimer && period == mTracker.currentPeriod()) { endPeriodTransition(); setIgnorePresentFencesInternal(false); mMoreSamplesNeeded = false; } else { - startPeriodTransition(period); + startPeriodTransitionInternal(period); } } -nsecs_t VSyncReactor::getPeriod() { - return mTracker.currentPeriod(); -} - -void VSyncReactor::beginResync() { - mTracker.resetModel(); -} - bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp, std::optional HwcVsyncPeriod) { if (!mPeriodConfirmationInProgress) { return false; @@ -164,13 +149,13 @@ bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp, std::optional allowancePercentRatio; auto const allowance = period * allowancePercentRatio.num / allowancePercentRatio.den; @@ -182,8 +167,8 @@ bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp, std::optional hwcVsyncPeriod, - bool* periodFlushed) { +bool VSyncReactor::addHwVsyncTimestamp(nsecs_t timestamp, std::optional hwcVsyncPeriod, + bool* periodFlushed) { assert(periodFlushed); std::lock_guard lock(mMutex); diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index 80b5232aa1..449d4c3bee 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -22,8 +22,8 @@ #include #include #include -#include "DispSync.h" #include "TimeKeeper.h" +#include "VsyncController.h" namespace android::scheduler { class Clock; @@ -31,32 +31,26 @@ class VSyncDispatch; class VSyncTracker; // TODO (b/145217110): consider renaming. -class VSyncReactor : public android::DispSync { +class VSyncReactor : public VsyncController { public: VSyncReactor(std::unique_ptr clock, VSyncTracker& tracker, size_t pendingFenceLimit, bool supportKernelIdleTimer); ~VSyncReactor(); - bool addPresentFence(const std::shared_ptr& fence) final; - void setIgnorePresentFences(bool ignoration) final; + bool addPresentFence(const std::shared_ptr& fence) final; + void setIgnorePresentFences(bool ignore) final; - nsecs_t computeNextRefresh(int periodOffset, nsecs_t now) const final; - nsecs_t expectedPresentTime(nsecs_t now) final; + void startPeriodTransition(nsecs_t period) final; - void setPeriod(nsecs_t period) final; - nsecs_t getPeriod() final; - - // TODO: (b/145626181) remove begin,endResync functions from DispSync i/f when possible. - void beginResync() final; - bool addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, - bool* periodFlushed) final; + bool addHwVsyncTimestamp(nsecs_t timestamp, std::optional hwcVsyncPeriod, + bool* periodFlushed) final; void dump(std::string& result) const final; private: - void setIgnorePresentFencesInternal(bool ignoration) REQUIRES(mMutex); + void setIgnorePresentFencesInternal(bool ignore) REQUIRES(mMutex); void updateIgnorePresentFencesInternal() REQUIRES(mMutex); - void startPeriodTransition(nsecs_t newPeriod) REQUIRES(mMutex); + void startPeriodTransitionInternal(nsecs_t newPeriod) REQUIRES(mMutex); void endPeriodTransition() REQUIRES(mMutex); bool periodConfirmed(nsecs_t vsync_timestamp, std::optional hwcVsyncPeriod) REQUIRES(mMutex); @@ -68,7 +62,7 @@ private: mutable std::mutex mMutex; bool mInternalIgnoreFences GUARDED_BY(mMutex) = false; bool mExternalIgnoreFences GUARDED_BY(mMutex) = false; - std::vector> mUnfiredFences GUARDED_BY(mMutex); + std::vector> mUnfiredFences GUARDED_BY(mMutex); bool mMoreSamplesNeeded GUARDED_BY(mMutex) = false; bool mPeriodConfirmationInProgress GUARDED_BY(mMutex) = false; diff --git a/services/surfaceflinger/Scheduler/VsyncController.h b/services/surfaceflinger/Scheduler/VsyncController.h new file mode 100644 index 0000000000..0f0df222f4 --- /dev/null +++ b/services/surfaceflinger/Scheduler/VsyncController.h @@ -0,0 +1,85 @@ +/* + * Copyright 2020 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 + +#include +#include +#include + +#include + +#include + +namespace android::scheduler { + +class FenceTime; + +class VsyncController { +public: + virtual ~VsyncController(); + + /* + * Adds a present fence to the model. The controller will use the fence time as + * a vsync signal. + * + * \param [in] fence The present fence given from the display + * \return True if the model needs more vsync signals to make + * an accurate prediction, + * False otherwise + */ + virtual bool addPresentFence(const std::shared_ptr&) = 0; + + /* + * Adds a hw sync timestamp to the model. The controller will use the timestamp + * time as a vsync signal. + * + * \param [in] timestamp The HW Vsync timestamp + * \param [in] hwcVsyncPeriod The Vsync period reported by composer, if available + * \param [out] periodFlushed True if the vsync period changed is completed + * \return True if the model needs more vsync signals to make + * an accurate prediction, + * False otherwise + */ + virtual bool addHwVsyncTimestamp(nsecs_t timestamp, std::optional hwcVsyncPeriod, + bool* periodFlushed) = 0; + + /* + * Inform the controller that the period is changing and the controller needs to recalibrate + * itself. The controller will end the period transition internally. + * + * \param [in] period The period that the system is changing into. + */ + virtual void startPeriodTransition(nsecs_t period) = 0; + + /* + * Tells the tracker to stop using present fences to get a vsync signal. + * + * \param [in] ignore Whether to ignore the present fences or not + */ + virtual void setIgnorePresentFences(bool ignore) = 0; + + virtual void dump(std::string& result) const = 0; + +protected: + VsyncController() = default; + VsyncController(VsyncController const&) = delete; + VsyncController& operator=(VsyncController const&) = delete; +}; + +} // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ccbb569500..0d5cacdcf3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -117,13 +117,13 @@ #include "Promise.h" #include "RefreshRateOverlay.h" #include "RegionSamplingThread.h" -#include "Scheduler/DispSync.h" #include "Scheduler/DispSyncSource.h" #include "Scheduler/EventThread.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/MessageQueue.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncConfiguration.h" +#include "Scheduler/VsyncController.h" #include "StartPropertySetThread.h" #include "SurfaceFlingerProperties.h" #include "SurfaceInterceptor.h" @@ -961,7 +961,7 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, // // Normally it's one full refresh period (to give SF a chance to // latch the buffer), but this can be reduced by configuring a - // DispSync offset. Any additional delays introduced by the hardware + // VsyncController offset. Any additional delays introduced by the hardware // composer or panel must be accounted for here. // // We add an additional 1ms to allow for processing time and @@ -979,7 +979,7 @@ status_t SurfaceFlinger::getDisplayStats(const sp&, DisplayStatInfo* st return BAD_VALUE; } - mScheduler->getDisplayStatInfo(stats); + mScheduler->getDisplayStatInfo(stats, systemTime()); return NO_ERROR; } @@ -1037,7 +1037,7 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { // switch. mScheduler->resyncToHardwareVsync(true, refreshRate.getVsyncPeriod()); // As we called to set period, we will call to onRefreshRateChangeCompleted once - // DispSync model is locked. + // VsyncController model is locked. modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated); updatePhaseConfiguration(refreshRate); @@ -1824,11 +1824,10 @@ nsecs_t SurfaceFlinger::previousFramePresentTime() { nsecs_t SurfaceFlinger::calculateExpectedPresentTime(nsecs_t now) const { DisplayStatInfo stats; - mScheduler->getDisplayStatInfo(&stats); - const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(now); + mScheduler->getDisplayStatInfo(&stats, now); // Inflate the expected present time if we're targetting the next vsync. - return mVsyncModulator->getVsyncConfig().sfOffset > 0 ? presentTime - : presentTime + stats.vsyncPeriod; + return mVsyncModulator->getVsyncConfig().sfOffset > 0 ? stats.vsyncTime + : stats.vsyncTime + stats.vsyncPeriod; } void SurfaceFlinger::onMessageReceived(int32_t what, nsecs_t expectedVSyncTime) { @@ -1874,7 +1873,7 @@ void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) { // smaller than a typical frame duration, but should not be so small // that it reports reasonable drift as a missed frame. DisplayStatInfo stats; - mScheduler->getDisplayStatInfo(&stats); + mScheduler->getDisplayStatInfo(&stats, systemTime()); const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2; const nsecs_t previousPresentTime = previousFramePresentTime(); const TracedOrdinal frameMissed = {"PrevFrameMissed", @@ -2247,7 +2246,7 @@ void SurfaceFlinger::postComposition() getBE().mDisplayTimeline.push(presentFenceTime); DisplayStatInfo stats; - mScheduler->getDisplayStatInfo(&stats); + mScheduler->getDisplayStatInfo(&stats, systemTime()); // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might // be sampled a little later than when we started doing work for this frame, @@ -4352,7 +4351,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { } else { static const std::unordered_map dumpers = { {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)}, - {"--dispsync"s, dumper([this](std::string& s) { mScheduler->dumpVSync(s); })}, + {"--dispsync"s, dumper([this](std::string& s) { mScheduler->dumpVsync(s); })}, {"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)}, {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)}, {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)}, @@ -4499,7 +4498,7 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { } mScheduler->dump(mAppConnectionHandle, result); - mScheduler->getPrimaryDispSync().dump(result); + mScheduler->dumpVsync(result); } void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c53ae3e118..9fddf552c4 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -219,7 +219,7 @@ public: // If fences from sync Framework are supported. static bool hasSyncFramework; - // The offset in nanoseconds to use when DispSync timestamps present fence + // The offset in nanoseconds to use when VsyncController timestamps present fence // signaling time. static int64_t dispSyncPresentTimeOffset; diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index 2e52155be4..fb08e695de 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -37,10 +37,10 @@ #include "SurfaceInterceptor.h" #include "DisplayHardware/ComposerHal.h" -#include "Scheduler/DispSync.h" #include "Scheduler/MessageQueue.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncConfiguration.h" +#include "Scheduler/VsyncController.h" namespace android::surfaceflinger { diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index a0dd9992bb..753476efe7 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -34,7 +34,6 @@ class BufferLayerConsumer; class EffectLayer; class ContainerLayer; class DisplayDevice; -class DispSync; class GraphicBuffer; class HWComposer; class IGraphicBufferConsumer; @@ -56,6 +55,7 @@ class CompositionEngine; namespace scheduler { class VsyncConfiguration; +class VsyncController; class RefreshRateConfigs; } // namespace scheduler diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 8d4aa0c4a6..a90f672898 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -68,13 +68,14 @@ cc_test { "mock/DisplayHardware/MockComposer.cpp", "mock/DisplayHardware/MockDisplay.cpp", "mock/DisplayHardware/MockPowerAdvisor.cpp", - "mock/MockDispSync.cpp", "mock/MockEventThread.cpp", + "mock/MockFrameTracer.cpp", "mock/MockMessageQueue.cpp", "mock/MockNativeWindowSurface.cpp", "mock/MockSurfaceInterceptor.cpp", "mock/MockTimeStats.cpp", - "mock/MockFrameTracer.cpp", + "mock/MockVsyncController.cpp", + "mock/MockVSyncTracker.cpp", "mock/system/window/MockNativeWindow.cpp", ], static_libs: [ diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 4843f059dc..159a215667 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -41,10 +41,10 @@ #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/DisplayHardware/MockPowerAdvisor.h" -#include "mock/MockDispSync.h" #include "mock/MockEventThread.h" #include "mock/MockMessageQueue.h" #include "mock/MockTimeStats.h" +#include "mock/MockVsyncController.h" #include "mock/system/window/MockNativeWindow.h" namespace android { @@ -142,17 +142,19 @@ public: new EventThreadConnection(sfEventThread.get(), ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); - auto primaryDispSync = std::make_unique(); + auto vsyncController = std::make_unique(); + auto vsyncTracker = std::make_unique(); - EXPECT_CALL(*primaryDispSync, computeNextRefresh(0, _)).WillRepeatedly(Return(0)); - EXPECT_CALL(*primaryDispSync, getPeriod()) + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, currentPeriod()) .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE)); - EXPECT_CALL(*primaryDispSync, expectedPresentTime(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); constexpr ISchedulerCallback* kCallback = nullptr; constexpr bool kHasMultipleConfigs = true; - mFlinger.setupScheduler(std::move(primaryDispSync), std::move(eventThread), - std::move(sfEventThread), kCallback, kHasMultipleConfigs); + mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), + std::move(eventThread), std::move(sfEventThread), kCallback, + kHasMultipleConfigs); // Layer history should be created if there are multiple configs. ASSERT_TRUE(mFlinger.scheduler()->hasLayerHistory()); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index b9c9fe7686..b939b9a197 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -45,12 +45,12 @@ #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/DisplayHardware/MockPowerAdvisor.h" -#include "mock/MockDispSync.h" #include "mock/MockEventThread.h" #include "mock/MockMessageQueue.h" #include "mock/MockNativeWindowSurface.h" #include "mock/MockSchedulerCallback.h" #include "mock/MockSurfaceInterceptor.h" +#include "mock/MockVsyncController.h" #include "mock/system/window/MockNativeWindow.h" namespace android { @@ -155,7 +155,8 @@ public: mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor(); - mock::DispSync* mPrimaryDispSync = new mock::DispSync; + mock::VsyncController* mVsyncController = new mock::VsyncController; + mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker; mock::SchedulerCallback mSchedulerCallback; mock::EventThread* mEventThread = new mock::EventThread; mock::EventThread* mSFEventThread = new mock::EventThread; @@ -213,7 +214,8 @@ void DisplayTransactionTest::injectMockScheduler() { .WillOnce(Return(new EventThreadConnection(mSFEventThread, ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); - mFlinger.setupScheduler(std::unique_ptr(mPrimaryDispSync), + mFlinger.setupScheduler(std::unique_ptr(mVsyncController), + std::unique_ptr(mVSyncTracker), std::unique_ptr(mEventThread), std::unique_ptr(mSFEventThread), &mSchedulerCallback); } @@ -3128,7 +3130,7 @@ TEST_F(DisplayTransactionTest, onInitializeDisplaysSetsUpPrimaryDisplay) { // processing. EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); - EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); // -------------------------------------------------------------------- // Invocation @@ -3259,15 +3261,14 @@ struct EventThreadIsSupportedVariant : public EventThreadBaseSupportedVariant { }; struct DispSyncIsSupportedVariant { - static void setupBeginResyncCallExpectations(DisplayTransactionTest* test) { - EXPECT_CALL(*test->mPrimaryDispSync, setPeriod(DEFAULT_REFRESH_RATE)).Times(1); - EXPECT_CALL(*test->mPrimaryDispSync, beginResync()).Times(1); + static void setupResetModelCallExpectations(DisplayTransactionTest* test) { + EXPECT_CALL(*test->mVsyncController, startPeriodTransition(DEFAULT_REFRESH_RATE)).Times(1); + EXPECT_CALL(*test->mVSyncTracker, resetModel()).Times(1); } }; struct DispSyncNotSupportedVariant { - static void setupBeginResyncCallExpectations(DisplayTransactionTest* /* test */) {} - + static void setupResetModelCallExpectations(DisplayTransactionTest* /* test */) {} }; // -------------------------------------------------------------------- @@ -3290,7 +3291,7 @@ struct TransitionOffToOnVariant : public TransitionVariantCommon static void setupCallExpectations(DisplayTransactionTest* test) { Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test); - Case::DispSync::setupBeginResyncCallExpectations(test); + Case::DispSync::setupResetModelCallExpectations(test); Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE); } }; @@ -3371,7 +3372,7 @@ struct TransitionDozeSuspendToOnVariant template static void setupCallExpectations(DisplayTransactionTest* test) { Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test); - Case::DispSync::setupBeginResyncCallExpectations(test); + Case::DispSync::setupResetModelCallExpectations(test); Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON); } }; diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp index f6bf05add8..409f90d9f9 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" @@ -31,8 +27,8 @@ #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" -#include "mock/MockDispSync.h" #include "mock/MockEventThread.h" +#include "mock/MockVsyncController.h" namespace android { @@ -64,7 +60,7 @@ protected: static constexpr int32_t PRIORITY_UNSET = -1; void setupScheduler(); - void setupComposer(int virtualDisplayCount); + void setupComposer(uint32_t virtualDisplayCount); sp createBufferQueueLayer(); sp createBufferStateLayer(); sp createEffectLayer(); @@ -139,17 +135,18 @@ void RefreshRateSelectionTest::setupScheduler() { .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); - auto primaryDispSync = std::make_unique(); + auto vsyncController = std::make_unique(); + auto vsyncTracker = std::make_unique(); - EXPECT_CALL(*primaryDispSync, computeNextRefresh(0, _)).WillRepeatedly(Return(0)); - EXPECT_CALL(*primaryDispSync, getPeriod()) + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, currentPeriod()) .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE)); - EXPECT_CALL(*primaryDispSync, expectedPresentTime(_)).WillRepeatedly(Return(0)); - mFlinger.setupScheduler(std::move(primaryDispSync), std::move(eventThread), - std::move(sfEventThread)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), + std::move(eventThread), std::move(sfEventThread)); } -void RefreshRateSelectionTest::setupComposer(int virtualDisplayCount) { +void RefreshRateSelectionTest::setupComposer(uint32_t virtualDisplayCount) { mComposer = new Hwc2::mock::Composer(); EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount)); mFlinger.setupComposer(std::unique_ptr(mComposer)); @@ -281,6 +278,3 @@ TEST_F(RefreshRateSelectionTest, testPriorityOnEffectLayers) { } // namespace } // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 6c01f85fc7..d4591fc4f2 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -32,9 +32,9 @@ #pragma clang diagnostic pop // ignored "-Wconversion" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" -#include "mock/MockDispSync.h" #include "mock/MockEventThread.h" #include "mock/MockMessageQueue.h" +#include "mock/MockVsyncController.h" namespace android { @@ -175,14 +175,15 @@ void SetFrameRateTest::setupScheduler() { .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); - auto primaryDispSync = std::make_unique(); + auto vsyncController = std::make_unique(); + auto vsyncTracker = std::make_unique(); - EXPECT_CALL(*primaryDispSync, computeNextRefresh(0, _)).WillRepeatedly(Return(0)); - EXPECT_CALL(*primaryDispSync, getPeriod()) + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, currentPeriod()) .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE)); - EXPECT_CALL(*primaryDispSync, expectedPresentTime(_)).WillRepeatedly(Return(0)); - mFlinger.setupScheduler(std::move(primaryDispSync), std::move(eventThread), - std::move(sfEventThread)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), + std::move(eventThread), std::move(sfEventThread)); } void SetFrameRateTest::setupComposer(uint32_t virtualDisplayCount) { diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index ebb2d76d1e..db3e0bd525 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -19,12 +19,13 @@ #include #include -#include "Scheduler/DispSync.h" #include "Scheduler/EventThread.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VSyncTracker.h" -#include "mock/MockDispSync.h" +#include "Scheduler/VsyncController.h" +#include "mock/MockVSyncTracker.h" +#include "mock/MockVsyncController.h" namespace android { @@ -32,14 +33,16 @@ class TestableScheduler : public Scheduler { public: TestableScheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback, bool useContentDetectionV2) - : TestableScheduler(std::make_unique(), configs, callback, + : TestableScheduler(std::make_unique(), + std::make_unique(), configs, callback, useContentDetectionV2) {} - TestableScheduler(std::unique_ptr primaryDispSync, + TestableScheduler(std::unique_ptr vsyncController, + std::unique_ptr vsyncTracker, const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback, bool useContentDetectionV2) - : Scheduler({std::move(primaryDispSync), nullptr, nullptr}, configs, callback, - createLayerHistory(configs, useContentDetectionV2), + : Scheduler({std::move(vsyncController), std::move(vsyncTracker), nullptr}, configs, + callback, createLayerHistory(configs, useContentDetectionV2), {.supportKernelTimer = false, .useContentDetection = true, .useContentDetectionV2 = useContentDetectionV2}) {} @@ -95,7 +98,7 @@ public: // not report a leaked object, since the Scheduler instance may // still be referenced by something despite our best efforts to destroy // it after each test is done. - mVsyncSchedule.sync.reset(); + mVsyncSchedule.controller.reset(); mConnections.clear(); } }; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 8c4232df88..b024568cbc 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -189,7 +189,8 @@ public: } // The ISchedulerCallback argument can be nullptr for a no-op implementation. - void setupScheduler(std::unique_ptr primaryDispSync, + void setupScheduler(std::unique_ptr vsyncController, + std::unique_ptr vsyncTracker, std::unique_ptr appEventThread, std::unique_ptr sfEventThread, ISchedulerCallback* callback = nullptr, bool hasMultipleConfigs = false) { @@ -217,9 +218,9 @@ public: mFlinger->mVsyncModulator.emplace(mFlinger->mVsyncConfiguration->getCurrentConfigs()); constexpr bool kUseContentDetectionV2 = false; - mScheduler = - new TestableScheduler(std::move(primaryDispSync), *mFlinger->mRefreshRateConfigs, - *(callback ?: this), kUseContentDetectionV2); + mScheduler = new TestableScheduler(std::move(vsyncController), std::move(vsyncTracker), + *mFlinger->mRefreshRateConfigs, *(callback ?: this), + kUseContentDetectionV2); mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread)); mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread)); diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 44b3dc0ea1..28415bcb12 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -31,9 +31,9 @@ #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" -#include "mock/MockDispSync.h" #include "mock/MockEventThread.h" #include "mock/MockMessageQueue.h" +#include "mock/MockVsyncController.h" namespace android { @@ -75,11 +75,12 @@ public: new EventThreadConnection(sfEventThread.get(), ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); - EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0, _)).WillRepeatedly(Return(0)); - EXPECT_CALL(*mPrimaryDispSync, getPeriod()) + EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*mVSyncTracker, currentPeriod()) .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE)); - mFlinger.setupScheduler(std::unique_ptr(mPrimaryDispSync), + mFlinger.setupScheduler(std::unique_ptr(mVsyncController), + std::unique_ptr(mVSyncTracker), std::move(eventThread), std::move(sfEventThread)); } @@ -89,7 +90,8 @@ public: std::unique_ptr mEventThread = std::make_unique(); mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); - mock::DispSync* mPrimaryDispSync = new mock::DispSync(); + mock::VsyncController* mVsyncController = new mock::VsyncController(); + mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker(); struct TransactionInfo { Vector states; @@ -123,7 +125,7 @@ public: ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); - EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_)).WillOnce(Return(systemTime())); + EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillOnce(Return(systemTime())); TransactionInfo transaction; setupSingle(transaction, flags, syncInputWindows, /*desiredPresentTime*/ -1); @@ -156,7 +158,7 @@ public: // first check will see desired present time has not passed, // but afterwards it will look like the desired present time has passed nsecs_t time = systemTime(); - EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_)) + EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)) .WillOnce(Return(time + nsecs_t(5 * 1e8))); TransactionInfo transaction; setupSingle(transaction, flags, syncInputWindows, @@ -179,7 +181,7 @@ public: // called in SurfaceFlinger::signalTransaction nsecs_t time = systemTime(); EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); - EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_)) + EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)) .WillOnce(Return(time + nsecs_t(5 * 1e8))); // transaction that should go on the pending thread TransactionInfo transactionA; @@ -244,7 +246,7 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); // nsecs_t time = systemTime(); - EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_)) + EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)) .WillOnce(Return(nsecs_t(5 * 1e8))) .WillOnce(Return(s2ns(2))); TransactionInfo transactionA; // transaction to go on pending queue diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp index 3408fed3e0..1e5139c49e 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp @@ -65,7 +65,7 @@ public: bool addVsyncTimestamp(nsecs_t) final { return true; } nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t time_point) const final { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); auto const normalized_to_base = time_point - mBase; auto const floor = (normalized_to_base) % mPeriod; if (floor == 0) { @@ -75,13 +75,13 @@ public: } void set_interval(nsecs_t interval, nsecs_t last_known) { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); mPeriod = interval; mBase = last_known; } nsecs_t currentPeriod() const final { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); return mPeriod; } @@ -118,11 +118,11 @@ public: .earliestVsync = systemTime(SYSTEM_TIME_MONOTONIC) + mWorkload + mReadyDuration}); for (auto i = 0u; i < iterations - 1; i++) { - std::unique_lock lk(mMutex); - mCv.wait(lk, [&] { return mCalled; }); + std::unique_lock lock(mMutex); + mCv.wait(lock, [&] { return mCalled; }); mCalled = false; auto last = mLastTarget; - lk.unlock(); + lock.unlock(); onEachFrame(last); @@ -132,8 +132,8 @@ public: } // wait for the last callback. - std::unique_lock lk(mMutex); - mCv.wait(lk, [&] { return mCalled; }); + std::unique_lock lock(mMutex); + mCv.wait(lock, [&] { return mCalled; }); } void with_callback_times(std::function const&)> const& fn) const { @@ -142,7 +142,7 @@ public: private: void callback_called(nsecs_t time) { - std::lock_guard lk(mMutex); + std::lock_guard lock(mMutex); mCallbackTimes.push_back(time); mCalled = true; mLastTarget = time; diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index 24e243fe77..69731fdbed 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -144,18 +144,18 @@ public: operator VSyncDispatch::CallbackToken() const { return mToken; } void pause(nsecs_t, nsecs_t) { - std::unique_lock lk(mMutex); + std::unique_lock lock(mMutex); mPause = true; mCv.notify_all(); - mCv.wait_for(lk, mPauseAmount, [this] { return !mPause; }); + mCv.wait_for(lock, mPauseAmount, [this] { return !mPause; }); mResourcePresent = (mResource.lock() != nullptr); } bool waitForPause() { - std::unique_lock lk(mMutex); - auto waiting = mCv.wait_for(lk, 10s, [this] { return mPause; }); + std::unique_lock lock(mMutex); + auto waiting = mCv.wait_for(lock, 10s, [this] { return mPause; }); return waiting; } @@ -164,7 +164,7 @@ public: bool resourcePresent() { return mResourcePresent; } void unpause() { - std::unique_lock lk(mMutex); + std::unique_lock lock(mMutex); mPause = false; mCv.notify_all(); } diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index 0eae01e138..0dcaf26bae 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -70,24 +70,24 @@ public: MOCK_CONST_METHOD1(dump, void(std::string&)); }; -std::shared_ptr generateInvalidFence() { +std::shared_ptr generateInvalidFence() { sp fence = new Fence(); - return std::make_shared(fence); + return std::make_shared(fence); } -std::shared_ptr generatePendingFence() { +std::shared_ptr generatePendingFence() { sp fence = new Fence(dup(fileno(tmpfile()))); - return std::make_shared(fence); + return std::make_shared(fence); } -void signalFenceWithTime(std::shared_ptr const& fence, nsecs_t time) { - FenceTime::Snapshot snap(time); +void signalFenceWithTime(std::shared_ptr const& fence, nsecs_t time) { + android::FenceTime::Snapshot snap(time); fence->applyTrustedSnapshot(snap); } -std::shared_ptr generateSignalledFenceWithTime(nsecs_t time) { +std::shared_ptr generateSignalledFenceWithTime(nsecs_t time) { sp fence = new Fence(dup(fileno(tmpfile()))); - std::shared_ptr ft = std::make_shared(fence); + std::shared_ptr ft = std::make_shared(fence); signalFenceWithTime(ft, time); return ft; } @@ -152,7 +152,7 @@ TEST_F(VSyncReactorTest, addingPendingFenceAddsSignalled) { } TEST_F(VSyncReactorTest, limitsPendingFences) { - std::array, kPendingLimit * 2> fences; + std::array, kPendingLimit * 2> fences; std::array fakeTimes; std::generate(fences.begin(), fences.end(), [] { return generatePendingFence(); }); std::generate(fakeTimes.begin(), fakeTimes.end(), [i = 10]() mutable { @@ -193,86 +193,48 @@ TEST_F(VSyncReactorTest, ignoresProperlyAfterAPeriodConfirmation) { mReactor.setIgnorePresentFences(true); nsecs_t const newPeriod = 5000; - mReactor.setPeriod(newPeriod); + mReactor.startPeriodTransition(newPeriod); - EXPECT_TRUE(mReactor.addResyncSample(0, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(0, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_FALSE(mReactor.addResyncSample(newPeriod, std::nullopt, &periodFlushed)); + EXPECT_FALSE(mReactor.addHwVsyncTimestamp(newPeriod, std::nullopt, &periodFlushed)); EXPECT_TRUE(periodFlushed); EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); } -TEST_F(VSyncReactorTest, queriesTrackerForNextRefreshNow) { - nsecs_t const fakeTimestamp = 4839; - EXPECT_CALL(*mMockTracker, currentPeriod()).Times(0); - EXPECT_CALL(*mMockTracker, nextAnticipatedVSyncTimeFrom(_)) - .Times(1) - .WillOnce(Return(fakeTimestamp)); - - EXPECT_THAT(mReactor.computeNextRefresh(0, mMockClock->now()), Eq(fakeTimestamp)); -} - -TEST_F(VSyncReactorTest, queriesTrackerForExpectedPresentTime) { - nsecs_t const fakeTimestamp = 4839; - EXPECT_CALL(*mMockTracker, currentPeriod()).Times(0); - EXPECT_CALL(*mMockTracker, nextAnticipatedVSyncTimeFrom(_)) - .Times(1) - .WillOnce(Return(fakeTimestamp)); - - EXPECT_THAT(mReactor.expectedPresentTime(mMockClock->now()), Eq(fakeTimestamp)); -} - -TEST_F(VSyncReactorTest, queriesTrackerForNextRefreshFuture) { - nsecs_t const fakeTimestamp = 4839; - nsecs_t const fakePeriod = 1010; - nsecs_t const mFakeNow = 2214; - int const numPeriodsOut = 3; - EXPECT_CALL(*mMockClock, now()).WillOnce(Return(mFakeNow)); - EXPECT_CALL(*mMockTracker, currentPeriod()).WillOnce(Return(fakePeriod)); - EXPECT_CALL(*mMockTracker, nextAnticipatedVSyncTimeFrom(mFakeNow + numPeriodsOut * fakePeriod)) - .WillOnce(Return(fakeTimestamp)); - EXPECT_THAT(mReactor.computeNextRefresh(numPeriodsOut, mMockClock->now()), Eq(fakeTimestamp)); -} - -TEST_F(VSyncReactorTest, getPeriod) { - nsecs_t const fakePeriod = 1010; - EXPECT_CALL(*mMockTracker, currentPeriod()).WillOnce(Return(fakePeriod)); - EXPECT_THAT(mReactor.getPeriod(), Eq(fakePeriod)); -} - TEST_F(VSyncReactorTest, setPeriodCalledOnceConfirmedChange) { nsecs_t const newPeriod = 5000; EXPECT_CALL(*mMockTracker, setPeriod(_)).Times(0); - mReactor.setPeriod(newPeriod); + mReactor.startPeriodTransition(newPeriod); bool periodFlushed = true; - EXPECT_TRUE(mReactor.addResyncSample(10000, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(10000, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_TRUE(mReactor.addResyncSample(20000, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(20000, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); Mock::VerifyAndClearExpectations(mMockTracker.get()); EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1); - EXPECT_FALSE(mReactor.addResyncSample(25000, std::nullopt, &periodFlushed)); + EXPECT_FALSE(mReactor.addHwVsyncTimestamp(25000, std::nullopt, &periodFlushed)); EXPECT_TRUE(periodFlushed); } TEST_F(VSyncReactorTest, changingPeriodBackAbortsConfirmationProcess) { nsecs_t sampleTime = 0; nsecs_t const newPeriod = 5000; - mReactor.setPeriod(newPeriod); + mReactor.startPeriodTransition(newPeriod); bool periodFlushed = true; - EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - mReactor.setPeriod(period); - EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed)); + mReactor.startPeriodTransition(period); + EXPECT_FALSE(mReactor.addHwVsyncTimestamp(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); } @@ -281,16 +243,18 @@ TEST_F(VSyncReactorTest, changingToAThirdPeriodWillWaitForLastPeriod) { nsecs_t const secondPeriod = 5000; nsecs_t const thirdPeriod = 2000; - mReactor.setPeriod(secondPeriod); + mReactor.startPeriodTransition(secondPeriod); bool periodFlushed = true; - EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - mReactor.setPeriod(thirdPeriod); - EXPECT_TRUE(mReactor.addResyncSample(sampleTime += secondPeriod, std::nullopt, &periodFlushed)); + mReactor.startPeriodTransition(thirdPeriod); + EXPECT_TRUE( + mReactor.addHwVsyncTimestamp(sampleTime += secondPeriod, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_FALSE(mReactor.addResyncSample(sampleTime += thirdPeriod, std::nullopt, &periodFlushed)); + EXPECT_FALSE( + mReactor.addHwVsyncTimestamp(sampleTime += thirdPeriod, std::nullopt, &periodFlushed)); EXPECT_TRUE(periodFlushed); } @@ -305,9 +269,10 @@ TEST_F(VSyncReactorTest, reportedBadTimestampFromPredictorWillReactivateHwVSync) nsecs_t skewyPeriod = period >> 1; bool periodFlushed = false; nsecs_t sampleTime = 0; - EXPECT_TRUE(mReactor.addResyncSample(sampleTime += skewyPeriod, std::nullopt, &periodFlushed)); + EXPECT_TRUE( + mReactor.addHwVsyncTimestamp(sampleTime += skewyPeriod, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed)); + EXPECT_FALSE(mReactor.addHwVsyncTimestamp(sampleTime += period, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); } @@ -325,22 +290,22 @@ TEST_F(VSyncReactorTest, reportedBadTimestampFromPredictorWillReactivateHwVSyncP TEST_F(VSyncReactorTest, presentFenceAdditionDoesNotInterruptConfirmationProcess) { nsecs_t const newPeriod = 5000; - mReactor.setPeriod(newPeriod); + mReactor.startPeriodTransition(newPeriod); EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); } TEST_F(VSyncReactorTest, setPeriodCalledFirstTwoEventsNewPeriod) { nsecs_t const newPeriod = 5000; EXPECT_CALL(*mMockTracker, setPeriod(_)).Times(0); - mReactor.setPeriod(newPeriod); + mReactor.startPeriodTransition(newPeriod); bool periodFlushed = true; - EXPECT_TRUE(mReactor.addResyncSample(5000, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(5000, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); Mock::VerifyAndClearExpectations(mMockTracker.get()); EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1); - EXPECT_FALSE(mReactor.addResyncSample(10000, std::nullopt, &periodFlushed)); + EXPECT_FALSE(mReactor.addHwVsyncTimestamp(10000, std::nullopt, &periodFlushed)); EXPECT_TRUE(periodFlushed); } @@ -349,7 +314,7 @@ TEST_F(VSyncReactorTest, addResyncSampleTypical) { bool periodFlushed = false; EXPECT_CALL(*mMockTracker, addVsyncTimestamp(fakeTimestamp)); - EXPECT_FALSE(mReactor.addResyncSample(fakeTimestamp, std::nullopt, &periodFlushed)); + EXPECT_FALSE(mReactor.addHwVsyncTimestamp(fakeTimestamp, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); } @@ -357,23 +322,23 @@ TEST_F(VSyncReactorTest, addResyncSamplePeriodChanges) { bool periodFlushed = false; nsecs_t const newPeriod = 4000; - mReactor.setPeriod(newPeriod); + mReactor.startPeriodTransition(newPeriod); auto time = 0; auto constexpr numTimestampSubmissions = 10; for (auto i = 0; i < numTimestampSubmissions; i++) { time += period; - EXPECT_TRUE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); } time += newPeriod; - EXPECT_FALSE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed)); + EXPECT_FALSE(mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed)); EXPECT_TRUE(periodFlushed); for (auto i = 0; i < numTimestampSubmissions; i++) { time += newPeriod; - EXPECT_FALSE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed)); + EXPECT_FALSE(mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed)); EXPECT_FALSE(periodFlushed); } } @@ -382,14 +347,14 @@ TEST_F(VSyncReactorTest, addPresentFenceWhileAwaitingPeriodConfirmationRequestsH auto time = 0; bool periodFlushed = false; nsecs_t const newPeriod = 4000; - mReactor.setPeriod(newPeriod); + mReactor.startPeriodTransition(newPeriod); time += period; - mReactor.addResyncSample(time, std::nullopt, &periodFlushed); + mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed); EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); time += newPeriod; - mReactor.addResyncSample(time, std::nullopt, &periodFlushed); + mReactor.addHwVsyncTimestamp(time, std::nullopt, &periodFlushed); EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); } @@ -398,7 +363,7 @@ TEST_F(VSyncReactorTest, hwVsyncIsRequestedForTracker) { auto time = 0; bool periodFlushed = false; nsecs_t const newPeriod = 4000; - mReactor.setPeriod(newPeriod); + mReactor.startPeriodTransition(newPeriod); static auto constexpr numSamplesWithNewPeriod = 4; Sequence seq; @@ -412,20 +377,20 @@ TEST_F(VSyncReactorTest, hwVsyncIsRequestedForTracker) { .WillRepeatedly(Return(false)); EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(numSamplesWithNewPeriod); - EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += period, std::nullopt, &periodFlushed)); - EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += period, std::nullopt, &periodFlushed)); // confirmed period, but predictor wants numRequest samples. This one and prior are valid. - EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod, std::nullopt, &periodFlushed)); - EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod, std::nullopt, &periodFlushed)); - EXPECT_FALSE(mReactor.addResyncSample(time += newPeriod, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += newPeriod, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += newPeriod, std::nullopt, &periodFlushed)); + EXPECT_FALSE(mReactor.addHwVsyncTimestamp(time += newPeriod, std::nullopt, &periodFlushed)); } TEST_F(VSyncReactorTest, hwVsyncturnsOffOnConfirmationWhenTrackerDoesntRequest) { auto time = 0; bool periodFlushed = false; nsecs_t const newPeriod = 4000; - mReactor.setPeriod(newPeriod); + mReactor.startPeriodTransition(newPeriod); Sequence seq; EXPECT_CALL(*mMockTracker, needsMoreSamples()) @@ -434,9 +399,9 @@ TEST_F(VSyncReactorTest, hwVsyncturnsOffOnConfirmationWhenTrackerDoesntRequest) .WillRepeatedly(Return(false)); EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(2); - EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed)); - EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed)); - EXPECT_FALSE(mReactor.addResyncSample(time += newPeriod, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += period, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += period, std::nullopt, &periodFlushed)); + EXPECT_FALSE(mReactor.addHwVsyncTimestamp(time += newPeriod, std::nullopt, &periodFlushed)); } TEST_F(VSyncReactorTest, hwVsyncIsRequestedForTrackerMultiplePeriodChanges) { @@ -445,7 +410,7 @@ TEST_F(VSyncReactorTest, hwVsyncIsRequestedForTrackerMultiplePeriodChanges) { nsecs_t const newPeriod1 = 4000; nsecs_t const newPeriod2 = 7000; - mReactor.setPeriod(newPeriod1); + mReactor.startPeriodTransition(newPeriod1); Sequence seq; EXPECT_CALL(*mMockTracker, needsMoreSamples()) @@ -458,22 +423,17 @@ TEST_F(VSyncReactorTest, hwVsyncIsRequestedForTrackerMultiplePeriodChanges) { .WillRepeatedly(Return(false)); EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(7); - EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed)); - EXPECT_TRUE(mReactor.addResyncSample(time += period, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += period, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += period, std::nullopt, &periodFlushed)); // confirmed period, but predictor wants numRequest samples. This one and prior are valid. - EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod1, std::nullopt, &periodFlushed)); - EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod1, std::nullopt, &periodFlushed)); - - mReactor.setPeriod(newPeriod2); - EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod1, std::nullopt, &periodFlushed)); - EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod2, std::nullopt, &periodFlushed)); - EXPECT_TRUE(mReactor.addResyncSample(time += newPeriod2, std::nullopt, &periodFlushed)); - EXPECT_FALSE(mReactor.addResyncSample(time += newPeriod2, std::nullopt, &periodFlushed)); -} - -TEST_F(VSyncReactorTest, beginResyncResetsModel) { - EXPECT_CALL(*mMockTracker, resetModel()); - mReactor.beginResync(); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += newPeriod1, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += newPeriod1, std::nullopt, &periodFlushed)); + + mReactor.startPeriodTransition(newPeriod2); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += newPeriod1, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += newPeriod2, std::nullopt, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(time += newPeriod2, std::nullopt, &periodFlushed)); + EXPECT_FALSE(mReactor.addHwVsyncTimestamp(time += newPeriod2, std::nullopt, &periodFlushed)); } TEST_F(VSyncReactorTest, periodChangeWithGivenVsyncPeriod) { @@ -482,13 +442,13 @@ TEST_F(VSyncReactorTest, periodChangeWithGivenVsyncPeriod) { mReactor.setIgnorePresentFences(true); nsecs_t const newPeriod = 5000; - mReactor.setPeriod(newPeriod); + mReactor.startPeriodTransition(newPeriod); - EXPECT_TRUE(mReactor.addResyncSample(0, 0, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(0, 0, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_TRUE(mReactor.addResyncSample(newPeriod, 0, &periodFlushed)); + EXPECT_TRUE(mReactor.addHwVsyncTimestamp(newPeriod, 0, &periodFlushed)); EXPECT_FALSE(periodFlushed); - EXPECT_FALSE(mReactor.addResyncSample(newPeriod, newPeriod, &periodFlushed)); + EXPECT_FALSE(mReactor.addHwVsyncTimestamp(newPeriod, newPeriod, &periodFlushed)); EXPECT_TRUE(periodFlushed); EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0))); @@ -505,25 +465,25 @@ TEST_F(VSyncReactorTest, periodIsMeasuredIfIgnoringComposer) { // First, set the same period, which should only be confirmed when we receive two // matching callbacks - idleReactor.setPeriod(10000); - EXPECT_TRUE(idleReactor.addResyncSample(0, 0, &periodFlushed)); + idleReactor.startPeriodTransition(10000); + EXPECT_TRUE(idleReactor.addHwVsyncTimestamp(0, 0, &periodFlushed)); EXPECT_FALSE(periodFlushed); // Correct period but incorrect timestamp delta - EXPECT_TRUE(idleReactor.addResyncSample(0, 10000, &periodFlushed)); + EXPECT_TRUE(idleReactor.addHwVsyncTimestamp(0, 10000, &periodFlushed)); EXPECT_FALSE(periodFlushed); // Correct period and correct timestamp delta - EXPECT_FALSE(idleReactor.addResyncSample(10000, 10000, &periodFlushed)); + EXPECT_FALSE(idleReactor.addHwVsyncTimestamp(10000, 10000, &periodFlushed)); EXPECT_TRUE(periodFlushed); // Then, set a new period, which should be confirmed as soon as we receive a callback // reporting the new period nsecs_t const newPeriod = 5000; - idleReactor.setPeriod(newPeriod); + idleReactor.startPeriodTransition(newPeriod); // Incorrect timestamp delta and period - EXPECT_TRUE(idleReactor.addResyncSample(20000, 10000, &periodFlushed)); + EXPECT_TRUE(idleReactor.addHwVsyncTimestamp(20000, 10000, &periodFlushed)); EXPECT_FALSE(periodFlushed); // Incorrect timestamp delta but correct period - EXPECT_FALSE(idleReactor.addResyncSample(20000, 5000, &periodFlushed)); + EXPECT_FALSE(idleReactor.addHwVsyncTimestamp(20000, 5000, &periodFlushed)); EXPECT_TRUE(periodFlushed); EXPECT_TRUE(idleReactor.addPresentFence(generateSignalledFenceWithTime(0))); diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp deleted file mode 100644 index bbd9f770f6..0000000000 --- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "mock/MockDispSync.h" -#include - -using namespace std::chrono_literals; -namespace android { -namespace mock { - -// Explicit default instantiation is recommended. -DispSync::DispSync() = default; -DispSync::~DispSync() = default; - -} // namespace mock -} // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h deleted file mode 100644 index 41445c8ae6..0000000000 --- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2018 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 - -#include "Scheduler/DispSync.h" - -namespace android { -namespace mock { - -class DispSync : public android::DispSync { -public: - DispSync(); - ~DispSync() override; - - MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr&)); - MOCK_METHOD0(beginResync, void()); - MOCK_METHOD3(addResyncSample, bool(nsecs_t, std::optional, bool*)); - MOCK_METHOD1(setPeriod, void(nsecs_t)); - MOCK_METHOD0(getPeriod, nsecs_t()); - MOCK_METHOD0(getIntendedPeriod, nsecs_t()); - MOCK_METHOD1(setRefreshSkipCount, void(int)); - MOCK_CONST_METHOD2(computeNextRefresh, nsecs_t(int, nsecs_t)); - MOCK_METHOD1(setIgnorePresentFences, void(bool)); - MOCK_METHOD1(expectedPresentTime, nsecs_t(nsecs_t)); - - MOCK_CONST_METHOD1(dump, void(std::string&)); -}; - -} // namespace mock -} // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.cpp b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.cpp new file mode 100644 index 0000000000..8a181232d8 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mock/MockVSyncTracker.h" +#include + +using namespace std::chrono_literals; +namespace android { +namespace mock { + +// Explicit default instantiation is recommended. +VSyncTracker::VSyncTracker() = default; +VSyncTracker::~VSyncTracker() = default; + +} // namespace mock +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h new file mode 100644 index 0000000000..03ddc8508f --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h @@ -0,0 +1,39 @@ +/* + * Copyright 2020 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 + +#include "Scheduler/VSyncTracker.h" + +namespace android::mock { + +class VSyncTracker : public android::scheduler::VSyncTracker { +public: + VSyncTracker(); + ~VSyncTracker() override; + + MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t)); + MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t)); + MOCK_CONST_METHOD0(currentPeriod, nsecs_t()); + MOCK_METHOD1(setPeriod, void(nsecs_t)); + MOCK_METHOD0(resetModel, void()); + MOCK_CONST_METHOD0(needsMoreSamples, bool()); + MOCK_CONST_METHOD1(dump, void(std::string&)); +}; + +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.cpp b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.cpp new file mode 100644 index 0000000000..25ae1bd312 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mock/MockVsyncController.h" +#include + +using namespace std::chrono_literals; +namespace android::mock { + +// Explicit default instantiation is recommended. +VsyncController::VsyncController() = default; +VsyncController::~VsyncController() = default; + +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h new file mode 100644 index 0000000000..1d87546a19 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 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 + +#include "Scheduler/VsyncController.h" + +namespace android { +namespace mock { + +class VsyncController : public android::scheduler::VsyncController { +public: + VsyncController(); + ~VsyncController() override; + + MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr&)); + MOCK_METHOD3(addHwVsyncTimestamp, bool(nsecs_t, std::optional, bool*)); + MOCK_METHOD1(startPeriodTransition, void(nsecs_t)); + MOCK_METHOD1(setIgnorePresentFences, void(bool)); + + MOCK_CONST_METHOD1(dump, void(std::string&)); +}; + +} // namespace mock +} // namespace android -- cgit v1.2.3-59-g8ed1b From 0390077c517d9643d21e3d23465cb89de982233d Mon Sep 17 00:00:00 2001 From: chaviw Date: Tue, 18 Aug 2020 12:34:51 -0700 Subject: Run screen capture requests asynchronously After posting the screenshot request to the main thread, don't wait for the results and instead just return immediately. The results from the screenshot will be sent through the requested ScreenCaptureListener In the current change, SurfaceComposerClient still waits for the result before returning so the JNI callers still get the screenshot synchronously. The call will become asynchronous in native in a later change. Test: SurfaceFlinger_test Test: adb shell screencap Test: power + volume down screenshot Test: Recents screenshots Change-Id: I5e352d6920b9298a0a376354f977f2ef7456841b --- services/surfaceflinger/RegionSamplingThread.cpp | 21 ++++- services/surfaceflinger/SurfaceFlinger.cpp | 105 +++++++++++------------ services/surfaceflinger/SurfaceFlinger.h | 14 +-- 3 files changed, 74 insertions(+), 66 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 6ba1942e2b..a2fc6925b8 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -446,9 +446,26 @@ void RegionSamplingThread::captureSample() { PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); } - ScreenCaptureResults captureResults; + class SyncScreenCaptureListener : public BnScreenCaptureListener { + public: + status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override { + resultsPromise.set_value(captureResults); + return NO_ERROR; + } + + ScreenCaptureResults waitForResults() { + std::future resultsFuture = resultsPromise.get_future(); + return resultsFuture.get(); + } + + private: + std::promise resultsPromise; + }; + + const sp captureListener = new SyncScreenCaptureListener(); mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - true /* regionSampling */, captureResults); + true /* regionSampling */, captureListener); + ScreenCaptureResults captureResults = captureListener->waitForResults(); std::vector activeDescriptors; for (const auto& descriptor : descriptors) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 240db35d44..9e5b8d8d7e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5530,12 +5530,9 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, auto traverseLayers = [this, args, layerStack](const LayerVector::Visitor& visitor) { traverseLayersInLayerStack(layerStack, args.uid, visitor); }; - ScreenCaptureResults captureResults; - status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, captureResults); - captureResults.result = status; - captureListener->onScreenCaptureComplete(captureResults); - return status; + + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, + args.pixelFormat, captureListener); } status_t SurfaceFlinger::setSchedFifo(bool enabled) { @@ -5608,12 +5605,8 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor); }; - ScreenCaptureResults captureResults; - status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, - ui::PixelFormat::RGBA_8888, captureResults); - captureResults.result = status; - captureListener->onScreenCaptureComplete(captureResults); - return status; + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, + ui::PixelFormat::RGBA_8888, captureListener); } status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, @@ -5704,7 +5697,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, captureSecureLayers); }); - auto traverseLayers = [parent, args, &excludeLayers](const LayerVector::Visitor& visitor) { + auto traverseLayers = [parent, args, excludeLayers](const LayerVector::Visitor& visitor) { parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { if (!layer->isVisible()) { return; @@ -5726,18 +5719,14 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, }); }; - ScreenCaptureResults captureResults; - status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, captureResults); - captureResults.result = status; - captureListener->onScreenCaptureComplete(captureResults); - return status; + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, + args.pixelFormat, captureListener); } status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, - ScreenCaptureResults& captureResults) { + const sp& captureListener) { ATRACE_CALL(); // TODO(b/116112787) Make buffer usage a parameter. @@ -5747,54 +5736,56 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(), static_cast(reqPixelFormat), 1 /* layerCount */, usage, "screenshot"); - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - false /* regionSampling */, captureResults); + false /* regionSampling */, captureListener); } status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, - const sp& buffer, bool regionSampling, - ScreenCaptureResults& captureResults) { - const int uid = IPCThreadState::self()->getCallingUid(); - const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM; + sp& buffer, bool regionSampling, + const sp& captureListener) { + ATRACE_CALL(); - status_t result; - int syncFd; - - do { - std::tie(result, syncFd) = - schedule([&]() -> std::pair { - if (mRefreshPending) { - ALOGW("Skipping screenshot for now"); - return {EAGAIN, -1}; - } - std::unique_ptr renderArea = renderAreaFuture.get(); - if (!renderArea) { - ALOGW("Skipping screen capture because of invalid render area."); - return {NO_MEMORY, -1}; - } + if (captureListener == nullptr) { + ALOGE("capture screen must provide a capture listener callback"); + return BAD_VALUE; + } - status_t result = NO_ERROR; - int fd = -1; + const int uid = IPCThreadState::self()->getCallingUid(); + const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM; - Mutex::Autolock lock(mStateLock); - renderArea->render([&] { - result = renderScreenImplLocked(*renderArea, traverseLayers, buffer.get(), - forSystem, &fd, regionSampling, - captureResults); - }); + static_cast(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable { + if (mRefreshPending) { + ALOGW("Skipping screenshot for now"); + captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, regionSampling, + captureListener); + return; + } + ScreenCaptureResults captureResults; + std::unique_ptr renderArea = renderAreaFuture.get(); + if (!renderArea) { + ALOGW("Skipping screen capture because of invalid render area."); + captureResults.result = NO_MEMORY; + captureListener->onScreenCaptureComplete(captureResults); + return; + } - return {result, fd}; - }).get(); - } while (result == EAGAIN); + status_t result = NO_ERROR; + int syncFd = -1; + renderArea->render([&] { + result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, forSystem, &syncFd, + regionSampling, captureResults); + }); - if (result == NO_ERROR) { - sync_wait(syncFd, -1); - close(syncFd); - } + if (result == NO_ERROR) { + sync_wait(syncFd, -1); + close(syncFd); + } + captureResults.result = result; + captureListener->onScreenCaptureComplete(captureResults); + })); - return result; + return NO_ERROR; } status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 37cafe9d75..e0a6073279 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -781,14 +781,14 @@ private: // Boot animation, on/off animations and screen capture void startBootAnim(); - status_t renderScreenImplLocked(const RenderArea& renderArea, - TraverseLayersFunction traverseLayers, - const sp& buffer, bool forSystem, int* outSyncFd, - bool regionSampling, ScreenCaptureResults& captureResults); + status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction, + const sp&, bool forSystem, int* outSyncFd, + bool regionSampling, ScreenCaptureResults&); status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, - ui::PixelFormat, ScreenCaptureResults& captureResults); - status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, const sp&, - bool regionSampling, ScreenCaptureResults& captureResults); + ui::PixelFormat, const sp&); + status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp&, + bool regionSampling, const sp&); + sp getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); sp getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock); -- cgit v1.2.3-59-g8ed1b From dcafa8d51740854c4d67fd12706e38db53a27afc Mon Sep 17 00:00:00 2001 From: chaviw Date: Tue, 18 Aug 2020 16:08:59 -0700 Subject: Update screen capture functions to accept a ScreenCaptureListener Move all screen capture functions to be asynchronous. The screen capture functions will no longer wait for screenshot results and will return immediately. Test: adb shell screencap Test: power + volume down Bug: 162367424 Change-Id: I9cbc833f802bda50d10d4521f61d262e9fd40bfc --- libs/gui/SurfaceComposerClient.cpp | 40 ++++------------------ libs/gui/include/gui/SurfaceComposerClient.h | 16 ++------- libs/gui/include/gui/SyncScreenCaptureListener.h | 40 ++++++++++++++++++++++ libs/gui/tests/BLASTBufferQueue_test.cpp | 1 + libs/gui/tests/Surface_test.cpp | 1 + services/surfaceflinger/RegionSamplingThread.cpp | 17 +-------- .../surfaceflinger/tests/utils/ScreenshotUtils.h | 18 +--------- 7 files changed, 53 insertions(+), 80 deletions(-) create mode 100644 libs/gui/include/gui/SyncScreenCaptureListener.h (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 65a1a01f2e..4c7d36573b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1921,57 +1921,29 @@ status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColo } // ---------------------------------------------------------------------------- -status_t SyncScreenCaptureListener::onScreenCaptureComplete( - const ScreenCaptureResults& captureResults) { - resultsPromise.set_value(captureResults); - return NO_ERROR; -} - -ScreenCaptureResults SyncScreenCaptureListener::waitForResults() { - std::future resultsFuture = resultsPromise.get_future(); - return resultsFuture.get(); -} status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs, - ScreenCaptureResults& captureResults) { + const sp& captureListener) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - sp captureListener = new SyncScreenCaptureListener(); - status_t status = s->captureDisplay(captureArgs, captureListener); - if (status != NO_ERROR) { - return status; - } - captureResults = captureListener->waitForResults(); - return captureResults.result; + return s->captureDisplay(captureArgs, captureListener); } status_t ScreenshotClient::captureDisplay(uint64_t displayOrLayerStack, - ScreenCaptureResults& captureResults) { + const sp& captureListener) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - sp captureListener = new SyncScreenCaptureListener(); - status_t status = s->captureDisplay(displayOrLayerStack, captureListener); - if (status != NO_ERROR) { - return status; - } - captureResults = captureListener->waitForResults(); - return captureResults.result; + return s->captureDisplay(displayOrLayerStack, captureListener); } status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs, - ScreenCaptureResults& captureResults) { + const sp& captureListener) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - sp captureListener = new SyncScreenCaptureListener(); - status_t status = s->captureLayers(captureArgs, captureListener); - if (status != NO_ERROR) { - return status; - } - captureResults = captureListener->waitForResults(); - return captureResults.result; + return s->captureLayers(captureArgs, captureListener); } } // namespace android diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 05151ba721..dc1d93642b 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -594,23 +593,14 @@ private: // --------------------------------------------------------------------------- -class SyncScreenCaptureListener : public BnScreenCaptureListener { -public: - status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override; - ScreenCaptureResults waitForResults(); - -private: - std::promise resultsPromise; -}; - class ScreenshotClient { public: static status_t captureDisplay(const DisplayCaptureArgs& captureArgs, - ScreenCaptureResults& captureResults); + const sp& captureListener); static status_t captureDisplay(uint64_t displayOrLayerStack, - ScreenCaptureResults& captureResults); + const sp& captureListener); static status_t captureLayers(const LayerCaptureArgs& captureArgs, - ScreenCaptureResults& captureResults); + const sp& captureListener); }; // --------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/SyncScreenCaptureListener.h b/libs/gui/include/gui/SyncScreenCaptureListener.h new file mode 100644 index 0000000000..2857996c23 --- /dev/null +++ b/libs/gui/include/gui/SyncScreenCaptureListener.h @@ -0,0 +1,40 @@ +/* + * Copyright 2020 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 +#include + +namespace android { + +class SyncScreenCaptureListener : public BnScreenCaptureListener { +public: + status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override { + resultsPromise.set_value(captureResults); + return NO_ERROR; + } + + ScreenCaptureResults waitForResults() { + std::future resultsFuture = resultsPromise.get_future(); + return resultsFuture.get(); + } + +private: + std::promise resultsPromise; +}; + +} // namespace android \ No newline at end of file diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 4a186b1e97..da0d5f85bb 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index aedba2aebd..dbede46e9f 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index a2fc6925b8..4dc20c44b8 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -446,22 +447,6 @@ void RegionSamplingThread::captureSample() { PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); } - class SyncScreenCaptureListener : public BnScreenCaptureListener { - public: - status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override { - resultsPromise.set_value(captureResults); - return NO_ERROR; - } - - ScreenCaptureResults waitForResults() { - std::future resultsFuture = resultsPromise.get_future(); - return resultsFuture.get(); - } - - private: - std::promise resultsPromise; - }; - const sp captureListener = new SyncScreenCaptureListener(); mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, true /* regionSampling */, captureListener); diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h index fbf5ecf388..167d7776cd 100644 --- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -15,32 +15,16 @@ */ #pragma once +#include #include #include #include -#include #include "TransactionUtils.h" namespace android { namespace { -class SyncScreenCaptureListener : public BnScreenCaptureListener { -public: - status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override { - resultsPromise.set_value(captureResults); - return NO_ERROR; - } - - ScreenCaptureResults waitForResults() { - std::future resultsFuture = resultsPromise.get_future(); - return resultsFuture.get(); - } - -private: - std::promise resultsPromise; -}; - // A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check // individual pixel values for testing purposes. class ScreenCapture : public RefBase { -- cgit v1.2.3-59-g8ed1b From 99eeeb8ddb1613fbc688bd37ebdaf8b66d105eed Mon Sep 17 00:00:00 2001 From: Chavi Weingarten Date: Thu, 10 Sep 2020 20:55:11 +0000 Subject: Revert "Update screen capture functions to accept a ScreenCaptur..." Revert submission 12404049-async_screencapture Reason for revert: 168149157, 168154840 Reverted Changes: I54c34003c:Send ScreenCaptureListener to native screen captur... I9cbc833f8:Update screen capture functions to accept a Screen... Change-Id: Ib5eacad84b794897173516e7d29b9af1eecace60 Bug: 168149157 Bug: 168154840 --- libs/gui/SurfaceComposerClient.cpp | 40 ++++++++++++++++++---- libs/gui/include/gui/SurfaceComposerClient.h | 16 +++++++-- libs/gui/include/gui/SyncScreenCaptureListener.h | 40 ---------------------- libs/gui/tests/BLASTBufferQueue_test.cpp | 1 - libs/gui/tests/Surface_test.cpp | 1 - services/surfaceflinger/RegionSamplingThread.cpp | 17 ++++++++- .../surfaceflinger/tests/utils/ScreenshotUtils.h | 18 +++++++++- 7 files changed, 80 insertions(+), 53 deletions(-) delete mode 100644 libs/gui/include/gui/SyncScreenCaptureListener.h (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 4c7d36573b..65a1a01f2e 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1921,29 +1921,57 @@ status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColo } // ---------------------------------------------------------------------------- +status_t SyncScreenCaptureListener::onScreenCaptureComplete( + const ScreenCaptureResults& captureResults) { + resultsPromise.set_value(captureResults); + return NO_ERROR; +} + +ScreenCaptureResults SyncScreenCaptureListener::waitForResults() { + std::future resultsFuture = resultsPromise.get_future(); + return resultsFuture.get(); +} status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs, - const sp& captureListener) { + ScreenCaptureResults& captureResults) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - return s->captureDisplay(captureArgs, captureListener); + sp captureListener = new SyncScreenCaptureListener(); + status_t status = s->captureDisplay(captureArgs, captureListener); + if (status != NO_ERROR) { + return status; + } + captureResults = captureListener->waitForResults(); + return captureResults.result; } status_t ScreenshotClient::captureDisplay(uint64_t displayOrLayerStack, - const sp& captureListener) { + ScreenCaptureResults& captureResults) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - return s->captureDisplay(displayOrLayerStack, captureListener); + sp captureListener = new SyncScreenCaptureListener(); + status_t status = s->captureDisplay(displayOrLayerStack, captureListener); + if (status != NO_ERROR) { + return status; + } + captureResults = captureListener->waitForResults(); + return captureResults.result; } status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs, - const sp& captureListener) { + ScreenCaptureResults& captureResults) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - return s->captureLayers(captureArgs, captureListener); + sp captureListener = new SyncScreenCaptureListener(); + status_t status = s->captureLayers(captureArgs, captureListener); + if (status != NO_ERROR) { + return status; + } + captureResults = captureListener->waitForResults(); + return captureResults.result; } } // namespace android diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index dc1d93642b..05151ba721 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -593,14 +594,23 @@ private: // --------------------------------------------------------------------------- +class SyncScreenCaptureListener : public BnScreenCaptureListener { +public: + status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override; + ScreenCaptureResults waitForResults(); + +private: + std::promise resultsPromise; +}; + class ScreenshotClient { public: static status_t captureDisplay(const DisplayCaptureArgs& captureArgs, - const sp& captureListener); + ScreenCaptureResults& captureResults); static status_t captureDisplay(uint64_t displayOrLayerStack, - const sp& captureListener); + ScreenCaptureResults& captureResults); static status_t captureLayers(const LayerCaptureArgs& captureArgs, - const sp& captureListener); + ScreenCaptureResults& captureResults); }; // --------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/SyncScreenCaptureListener.h b/libs/gui/include/gui/SyncScreenCaptureListener.h deleted file mode 100644 index 2857996c23..0000000000 --- a/libs/gui/include/gui/SyncScreenCaptureListener.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2020 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 -#include - -namespace android { - -class SyncScreenCaptureListener : public BnScreenCaptureListener { -public: - status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override { - resultsPromise.set_value(captureResults); - return NO_ERROR; - } - - ScreenCaptureResults waitForResults() { - std::future resultsFuture = resultsPromise.get_future(); - return resultsFuture.get(); - } - -private: - std::promise resultsPromise; -}; - -} // namespace android \ No newline at end of file diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index da0d5f85bb..4a186b1e97 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index dbede46e9f..aedba2aebd 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 4dc20c44b8..a2fc6925b8 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -447,6 +446,22 @@ void RegionSamplingThread::captureSample() { PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); } + class SyncScreenCaptureListener : public BnScreenCaptureListener { + public: + status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override { + resultsPromise.set_value(captureResults); + return NO_ERROR; + } + + ScreenCaptureResults waitForResults() { + std::future resultsFuture = resultsPromise.get_future(); + return resultsFuture.get(); + } + + private: + std::promise resultsPromise; + }; + const sp captureListener = new SyncScreenCaptureListener(); mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, true /* regionSampling */, captureListener); diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h index 167d7776cd..fbf5ecf388 100644 --- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -15,16 +15,32 @@ */ #pragma once -#include #include #include #include +#include #include "TransactionUtils.h" namespace android { namespace { +class SyncScreenCaptureListener : public BnScreenCaptureListener { +public: + status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override { + resultsPromise.set_value(captureResults); + return NO_ERROR; + } + + ScreenCaptureResults waitForResults() { + std::future resultsFuture = resultsPromise.get_future(); + return resultsFuture.get(); + } + +private: + std::promise resultsPromise; +}; + // A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check // individual pixel values for testing purposes. class ScreenCapture : public RefBase { -- cgit v1.2.3-59-g8ed1b From e7b9f278d924e10d53336e4c0a9bb6b11352a087 Mon Sep 17 00:00:00 2001 From: chaviw Date: Tue, 18 Aug 2020 16:08:59 -0700 Subject: Update screen capture functions to accept a ScreenCaptureListener Move all screen capture functions to be asynchronous. The screen capture functions will no longer wait for screenshot results and will return immediately. Test: adb shell screencap Test: power + volume down Bug: 162367424 Change-Id: I0fd32ede58d3d0a858fc0ce4aae058b9a9234c00 --- libs/gui/SurfaceComposerClient.cpp | 40 ++++------------------ libs/gui/include/gui/SurfaceComposerClient.h | 16 ++------- libs/gui/include/gui/SyncScreenCaptureListener.h | 40 ++++++++++++++++++++++ libs/gui/tests/BLASTBufferQueue_test.cpp | 1 + libs/gui/tests/Surface_test.cpp | 1 + services/surfaceflinger/RegionSamplingThread.cpp | 17 +-------- .../surfaceflinger/tests/utils/ScreenshotUtils.h | 18 +--------- 7 files changed, 53 insertions(+), 80 deletions(-) create mode 100644 libs/gui/include/gui/SyncScreenCaptureListener.h (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index ce2e5ed195..6d1f399460 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1923,57 +1923,29 @@ status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColo } // ---------------------------------------------------------------------------- -status_t SyncScreenCaptureListener::onScreenCaptureComplete( - const ScreenCaptureResults& captureResults) { - resultsPromise.set_value(captureResults); - return NO_ERROR; -} - -ScreenCaptureResults SyncScreenCaptureListener::waitForResults() { - std::future resultsFuture = resultsPromise.get_future(); - return resultsFuture.get(); -} status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs, - ScreenCaptureResults& captureResults) { + const sp& captureListener) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - sp captureListener = new SyncScreenCaptureListener(); - status_t status = s->captureDisplay(captureArgs, captureListener); - if (status != NO_ERROR) { - return status; - } - captureResults = captureListener->waitForResults(); - return captureResults.result; + return s->captureDisplay(captureArgs, captureListener); } status_t ScreenshotClient::captureDisplay(uint64_t displayOrLayerStack, - ScreenCaptureResults& captureResults) { + const sp& captureListener) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - sp captureListener = new SyncScreenCaptureListener(); - status_t status = s->captureDisplay(displayOrLayerStack, captureListener); - if (status != NO_ERROR) { - return status; - } - captureResults = captureListener->waitForResults(); - return captureResults.result; + return s->captureDisplay(displayOrLayerStack, captureListener); } status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs, - ScreenCaptureResults& captureResults) { + const sp& captureListener) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - sp captureListener = new SyncScreenCaptureListener(); - status_t status = s->captureLayers(captureArgs, captureListener); - if (status != NO_ERROR) { - return status; - } - captureResults = captureListener->waitForResults(); - return captureResults.result; + return s->captureLayers(captureArgs, captureListener); } } // namespace android diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index af37468c2d..6cac287d77 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -594,23 +593,14 @@ private: // --------------------------------------------------------------------------- -class SyncScreenCaptureListener : public BnScreenCaptureListener { -public: - status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override; - ScreenCaptureResults waitForResults(); - -private: - std::promise resultsPromise; -}; - class ScreenshotClient { public: static status_t captureDisplay(const DisplayCaptureArgs& captureArgs, - ScreenCaptureResults& captureResults); + const sp& captureListener); static status_t captureDisplay(uint64_t displayOrLayerStack, - ScreenCaptureResults& captureResults); + const sp& captureListener); static status_t captureLayers(const LayerCaptureArgs& captureArgs, - ScreenCaptureResults& captureResults); + const sp& captureListener); }; // --------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/SyncScreenCaptureListener.h b/libs/gui/include/gui/SyncScreenCaptureListener.h new file mode 100644 index 0000000000..2857996c23 --- /dev/null +++ b/libs/gui/include/gui/SyncScreenCaptureListener.h @@ -0,0 +1,40 @@ +/* + * Copyright 2020 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 +#include + +namespace android { + +class SyncScreenCaptureListener : public BnScreenCaptureListener { +public: + status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override { + resultsPromise.set_value(captureResults); + return NO_ERROR; + } + + ScreenCaptureResults waitForResults() { + std::future resultsFuture = resultsPromise.get_future(); + return resultsFuture.get(); + } + +private: + std::promise resultsPromise; +}; + +} // namespace android \ No newline at end of file diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 4a186b1e97..da0d5f85bb 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index aedba2aebd..dbede46e9f 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index a2fc6925b8..4dc20c44b8 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -446,22 +447,6 @@ void RegionSamplingThread::captureSample() { PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); } - class SyncScreenCaptureListener : public BnScreenCaptureListener { - public: - status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override { - resultsPromise.set_value(captureResults); - return NO_ERROR; - } - - ScreenCaptureResults waitForResults() { - std::future resultsFuture = resultsPromise.get_future(); - return resultsFuture.get(); - } - - private: - std::promise resultsPromise; - }; - const sp captureListener = new SyncScreenCaptureListener(); mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, true /* regionSampling */, captureListener); diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h index 1d94f21fb2..ca3551ed6c 100644 --- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -15,32 +15,16 @@ */ #pragma once +#include #include #include #include -#include #include "TransactionUtils.h" namespace android { namespace { -class SyncScreenCaptureListener : public BnScreenCaptureListener { -public: - status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override { - resultsPromise.set_value(captureResults); - return NO_ERROR; - } - - ScreenCaptureResults waitForResults() { - std::future resultsFuture = resultsPromise.get_future(); - return resultsFuture.get(); - } - -private: - std::promise resultsPromise; -}; - // A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check // individual pixel values for testing purposes. class ScreenCapture : public RefBase { -- cgit v1.2.3-59-g8ed1b From 67b1e2b6ba789f1d16e76f5d1d64cc6da00fa738 Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 26 Aug 2020 13:17:24 -0700 Subject: RE-on-SK The First Steps Lots of stuff is broken, but it puts things on screen Test: enable via setprop, force gpu comp Bug: 164223050 Change-Id: I443f751f5db95fbe9f4ee9294e3bace6e213545e --- libs/renderengine/Android.bp | 10 + libs/renderengine/RenderEngine.cpp | 7 + .../include/renderengine/RenderEngine.h | 1 + libs/renderengine/skia/SkiaGLRenderEngine.cpp | 539 +++++++++++++++++++++ libs/renderengine/skia/SkiaGLRenderEngine.h | 93 ++++ libs/renderengine/skia/SkiaRenderEngine.cpp | 26 + libs/renderengine/skia/SkiaRenderEngine.h | 71 +++ services/surfaceflinger/Android.bp | 5 +- .../CompositionEngine/src/RenderSurface.cpp | 10 + services/surfaceflinger/RegionSamplingThread.cpp | 3 +- 10 files changed, 763 insertions(+), 2 deletions(-) create mode 100644 libs/renderengine/skia/SkiaGLRenderEngine.cpp create mode 100644 libs/renderengine/skia/SkiaGLRenderEngine.h create mode 100644 libs/renderengine/skia/SkiaRenderEngine.cpp create mode 100644 libs/renderengine/skia/SkiaRenderEngine.h (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 9264bb6b0e..1ccbff16f7 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -31,6 +31,7 @@ cc_defaults { "libui", "libutils", ], + whole_static_libs: ["libskia"], local_include_dirs: ["include"], export_include_dirs: ["include"], } @@ -71,6 +72,14 @@ filegroup { ], } +filegroup { + name: "librenderengine_skia_sources", + srcs: [ + "skia/SkiaRenderEngine.cpp", + "skia/SkiaGLRenderEngine.cpp", + ], +} + cc_library_static { name: "librenderengine", defaults: ["librenderengine_defaults"], @@ -84,6 +93,7 @@ cc_library_static { ":librenderengine_sources", ":librenderengine_gl_sources", ":librenderengine_threaded_sources", + ":librenderengine_skia_sources", ], lto: { thin: true, diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index eb0074bc40..c6436cdbec 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -22,6 +22,8 @@ #include "gl/GLESRenderEngine.h" #include "threaded/RenderEngineThreaded.h" +#include "skia/SkiaGLRenderEngine.h" + namespace android { namespace renderengine { @@ -37,12 +39,17 @@ std::unique_ptr RenderEngine::create(const RenderEngineCreationArg if (strcmp(prop, "threaded") == 0) { renderEngineType = RenderEngineType::THREADED; } + if (strcmp(prop, "skiagl") == 0) { + renderEngineType = RenderEngineType::SKIA_GL; + } switch (renderEngineType) { case RenderEngineType::THREADED: ALOGD("Threaded RenderEngine with GLES Backend"); return renderengine::threaded::RenderEngineThreaded::create( [args]() { return android::renderengine::gl::GLESRenderEngine::create(args); }); + case RenderEngineType::SKIA_GL: + return renderengine::skia::SkiaGLRenderEngine::create(args); case RenderEngineType::GLES: default: ALOGD("RenderEngine with GLES Backend"); diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index a0e7ab7a43..3c90a3aeaf 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -73,6 +73,7 @@ public: enum class RenderEngineType { GLES = 1, THREADED = 2, + SKIA_GL = 3, }; static std::unique_ptr create(const RenderEngineCreationArgs& args); diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp new file mode 100644 index 0000000000..94ba15392f --- /dev/null +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -0,0 +1,539 @@ +/* + * Copyright 2020 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 "RenderEngine" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include + +#include +#include +#include +#include +#include +#include +#include "../gl/GLExtensions.h" +#include "SkiaGLRenderEngine.h" + +#include +#include + +#include +#include +#include + +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); + +bool checkGlError(const char* op, int lineNumber); + +namespace android { +namespace renderengine { +namespace skia { + +static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute, + EGLint wanted, EGLConfig* outConfig) { + EGLint numConfigs = -1, n = 0; + eglGetConfigs(dpy, nullptr, 0, &numConfigs); + std::vector configs(numConfigs, EGL_NO_CONFIG_KHR); + eglChooseConfig(dpy, attrs, configs.data(), configs.size(), &n); + configs.resize(n); + + if (!configs.empty()) { + if (attribute != EGL_NONE) { + for (EGLConfig config : configs) { + EGLint value = 0; + eglGetConfigAttrib(dpy, config, attribute, &value); + if (wanted == value) { + *outConfig = config; + return NO_ERROR; + } + } + } else { + // just pick the first one + *outConfig = configs[0]; + return NO_ERROR; + } + } + + return NAME_NOT_FOUND; +} + +static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType, + EGLConfig* config) { + // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if + // it is to be used with WIFI displays + status_t err; + EGLint wantedAttribute; + EGLint wantedAttributeValue; + + std::vector attribs; + if (renderableType) { + const ui::PixelFormat pixelFormat = static_cast(format); + const bool is1010102 = pixelFormat == ui::PixelFormat::RGBA_1010102; + + // Default to 8 bits per channel. + const EGLint tmpAttribs[] = { + EGL_RENDERABLE_TYPE, + renderableType, + EGL_RECORDABLE_ANDROID, + EGL_TRUE, + EGL_SURFACE_TYPE, + EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_FRAMEBUFFER_TARGET_ANDROID, + EGL_TRUE, + EGL_RED_SIZE, + is1010102 ? 10 : 8, + EGL_GREEN_SIZE, + is1010102 ? 10 : 8, + EGL_BLUE_SIZE, + is1010102 ? 10 : 8, + EGL_ALPHA_SIZE, + is1010102 ? 2 : 8, + EGL_NONE, + }; + std::copy(tmpAttribs, tmpAttribs + (sizeof(tmpAttribs) / sizeof(EGLint)), + std::back_inserter(attribs)); + wantedAttribute = EGL_NONE; + wantedAttributeValue = EGL_NONE; + } else { + // if no renderable type specified, fallback to a simplified query + wantedAttribute = EGL_NATIVE_VISUAL_ID; + wantedAttributeValue = format; + } + + err = selectConfigForAttribute(display, attribs.data(), wantedAttribute, wantedAttributeValue, + config); + if (err == NO_ERROR) { + EGLint caveat; + if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat)) + ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!"); + } + + return err; +} + +std::unique_ptr SkiaGLRenderEngine::create( + const RenderEngineCreationArgs& args) { + // initialize EGL for the default display + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (!eglInitialize(display, nullptr, nullptr)) { + LOG_ALWAYS_FATAL("failed to initialize EGL"); + } + + const auto eglVersion = eglQueryStringImplementationANDROID(display, EGL_VERSION); + if (!eglVersion) { + checkGlError(__FUNCTION__, __LINE__); + LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_VERSION) failed"); + } + + const auto eglExtensions = eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS); + if (!eglExtensions) { + checkGlError(__FUNCTION__, __LINE__); + LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_EXTENSIONS) failed"); + } + + auto& extensions = gl::GLExtensions::getInstance(); + extensions.initWithEGLStrings(eglVersion, eglExtensions); + + // The code assumes that ES2 or later is available if this extension is + // supported. + EGLConfig config = EGL_NO_CONFIG_KHR; + if (!extensions.hasNoConfigContext()) { + config = chooseEglConfig(display, args.pixelFormat, /*logConfig*/ true); + } + + bool useContextPriority = + extensions.hasContextPriority() && args.contextPriority == ContextPriority::HIGH; + EGLContext protectedContext = EGL_NO_CONTEXT; + if (args.enableProtectedContext && extensions.hasProtectedContent()) { + protectedContext = createEglContext(display, config, nullptr, useContextPriority, + Protection::PROTECTED); + ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context"); + } + + EGLContext ctxt = createEglContext(display, config, protectedContext, useContextPriority, + Protection::UNPROTECTED); + + // if can't create a GL context, we can only abort. + LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed"); + + EGLSurface placeholder = EGL_NO_SURFACE; + if (!extensions.hasSurfacelessContext()) { + placeholder = createPlaceholderEglPbufferSurface(display, config, args.pixelFormat, + Protection::UNPROTECTED); + LOG_ALWAYS_FATAL_IF(placeholder == EGL_NO_SURFACE, "can't create placeholder pbuffer"); + } + EGLBoolean success = eglMakeCurrent(display, placeholder, placeholder, ctxt); + LOG_ALWAYS_FATAL_IF(!success, "can't make placeholder pbuffer current"); + extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER), + glGetString(GL_VERSION), glGetString(GL_EXTENSIONS)); + + EGLSurface protectedPlaceholder = EGL_NO_SURFACE; + if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) { + protectedPlaceholder = createPlaceholderEglPbufferSurface(display, config, args.pixelFormat, + Protection::PROTECTED); + ALOGE_IF(protectedPlaceholder == EGL_NO_SURFACE, + "can't create protected placeholder pbuffer"); + } + + // initialize the renderer while GL is current + std::unique_ptr engine = + std::make_unique(args, display, config, ctxt, placeholder, + protectedContext, protectedPlaceholder); + + ALOGI("OpenGL ES informations:"); + ALOGI("vendor : %s", extensions.getVendor()); + ALOGI("renderer : %s", extensions.getRenderer()); + ALOGI("version : %s", extensions.getVersion()); + ALOGI("extensions: %s", extensions.getExtensions()); + ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize()); + ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims()); + + return engine; +} + +EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) { + status_t err; + EGLConfig config; + + // First try to get an ES3 config + err = selectEGLConfig(display, format, EGL_OPENGL_ES3_BIT, &config); + if (err != NO_ERROR) { + // If ES3 fails, try to get an ES2 config + err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config); + if (err != NO_ERROR) { + // If ES2 still doesn't work, probably because we're on the emulator. + // try a simplified query + ALOGW("no suitable EGLConfig found, trying a simpler query"); + err = selectEGLConfig(display, format, 0, &config); + if (err != NO_ERROR) { + // this EGL is too lame for android + LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up"); + } + } + } + + if (logConfig) { + // print some debugging info + EGLint r, g, b, a; + eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); + eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); + eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); + eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); + ALOGI("EGL information:"); + ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); + ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); + ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); + ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported"); + ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); + } + + return config; +} + +SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, + EGLConfig config, EGLContext ctxt, EGLSurface placeholder, + EGLContext protectedContext, EGLSurface protectedPlaceholder) + : renderengine::skia::SkiaRenderEngine(args), + mEGLDisplay(display), + mEGLConfig(config), + mEGLContext(ctxt), + mPlaceholderSurface(placeholder), + mProtectedEGLContext(protectedContext), + mProtectedPlaceholderSurface(protectedPlaceholder) { + // Suppress unused field warnings for things we definitely will need/use + // These EGL fields will all be needed for toggling between protected & unprotected contexts + // Or we need different RE instances for that + (void)mEGLDisplay; + (void)mEGLConfig; + (void)mEGLContext; + (void)mPlaceholderSurface; + (void)mProtectedEGLContext; + (void)mProtectedPlaceholderSurface; + + sk_sp glInterface(GrGLCreateNativeInterface()); + LOG_ALWAYS_FATAL_IF(!glInterface.get()); + + GrContextOptions options; + options.fPreferExternalImagesOverES3 = true; + options.fDisableDistanceFieldPaths = true; + mGrContext = GrDirectContext::MakeGL(std::move(glInterface), options); +} + +base::unique_fd SkiaGLRenderEngine::flush() { + ATRACE_CALL(); + if (!gl::GLExtensions::getInstance().hasNativeFenceSync()) { + return base::unique_fd(); + } + + EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); + if (sync == EGL_NO_SYNC_KHR) { + ALOGW("failed to create EGL native fence sync: %#x", eglGetError()); + return base::unique_fd(); + } + + // native fence fd will not be populated until flush() is done. + glFlush(); + + // get the fence fd + base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync)); + eglDestroySyncKHR(mEGLDisplay, sync); + if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { + ALOGW("failed to dup EGL native fence sync: %#x", eglGetError()); + } + + return fenceFd; +} + +bool SkiaGLRenderEngine::waitFence(base::unique_fd fenceFd) { + if (!gl::GLExtensions::getInstance().hasNativeFenceSync() || + !gl::GLExtensions::getInstance().hasWaitSync()) { + return false; + } + + // release the fd and transfer the ownership to EGLSync + EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd.release(), EGL_NONE}; + EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); + if (sync == EGL_NO_SYNC_KHR) { + ALOGE("failed to create EGL native fence sync: %#x", eglGetError()); + return false; + } + + // XXX: The spec draft is inconsistent as to whether this should return an + // EGLint or void. Ignore the return value for now, as it's not strictly + // needed. + eglWaitSyncKHR(mEGLDisplay, sync, 0); + EGLint error = eglGetError(); + eglDestroySyncKHR(mEGLDisplay, sync); + if (error != EGL_SUCCESS) { + ALOGE("failed to wait for EGL native fence sync: %#x", error); + return false; + } + + return true; +} + +static bool hasUsage(const AHardwareBuffer_Desc& desc, uint64_t usage) { + return !!(desc.usage & usage); +} + +void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { + std::lock_guard lock(mRenderingMutex); + mImageCache.erase(bufferId); +} + +status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, + const std::vector& layers, + const sp& buffer, + const bool useFramebufferCache, + base::unique_fd&& bufferFence, base::unique_fd* drawFence) { + ATRACE_NAME("SkiaGL::drawLayers"); + std::lock_guard lock(mRenderingMutex); + if (layers.empty()) { + ALOGV("Drawing empty layer stack"); + return NO_ERROR; + } + + if (bufferFence.get() >= 0) { + // Duplicate the fence for passing to waitFence. + base::unique_fd bufferFenceDup(dup(bufferFence.get())); + if (bufferFenceDup < 0 || !waitFence(std::move(bufferFenceDup))) { + ATRACE_NAME("Waiting before draw"); + sync_wait(bufferFence.get(), -1); + } + } + if (buffer == nullptr) { + ALOGE("No output buffer provided. Aborting GPU composition."); + return BAD_VALUE; + } + + AHardwareBuffer_Desc bufferDesc; + AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc); + + LOG_ALWAYS_FATAL_IF(!hasUsage(bufferDesc, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE), + "missing usage"); + + sk_sp surface; + if (useFramebufferCache) { + auto iter = mSurfaceCache.find(buffer->getId()); + if (iter != mSurfaceCache.end()) { + ALOGV("Cache hit!"); + surface = iter->second; + } + } + if (!surface) { + surface = SkSurface::MakeFromAHardwareBuffer(mGrContext.get(), buffer->toAHardwareBuffer(), + GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, + SkColorSpace::MakeSRGB(), nullptr); + if (useFramebufferCache && surface) { + ALOGD("Adding to cache"); + mSurfaceCache.insert({buffer->getId(), surface}); + } + } + if (!surface) { + ALOGE("Failed to make surface"); + return BAD_VALUE; + } + auto canvas = surface->getCanvas(); + + canvas->clipRect(SkRect::MakeLTRB(display.clip.left, display.clip.top, display.clip.right, + display.clip.bottom)); + canvas->drawColor(0, SkBlendMode::kSrc); + for (const auto& layer : layers) { + if (layer->source.buffer.buffer) { + ATRACE_NAME("DrawImage"); + const auto& item = layer->source.buffer; + sk_sp image; + auto iter = mImageCache.find(item.buffer->getId()); + if (iter != mImageCache.end()) { + image = iter->second; + } else { + image = SkImage::MakeFromAHardwareBuffer(item.buffer->toAHardwareBuffer(), + item.usePremultipliedAlpha + ? kPremul_SkAlphaType + : kUnpremul_SkAlphaType); + mImageCache.insert({item.buffer->getId(), image}); + } + const auto& bounds = layer->geometry.boundaries; + SkRect dest = SkRect::MakeLTRB(bounds.left, bounds.top, bounds.right, bounds.bottom); + canvas->drawImageRect(image, dest, nullptr); + } else { + ATRACE_NAME("DrawColor"); + SkPaint paint; + const auto color = layer->source.solidColor; + paint.setColor(SkColor4f{.fR = color.r, .fG = color.g, .fB = color.b, layer->alpha}); + } + } + { + ATRACE_NAME("flush surface"); + surface->flush(); + } + + if (drawFence != nullptr) { + *drawFence = flush(); + } + + // If flush failed or we don't support native fences, we need to force the + // gl command stream to be executed. + bool requireSync = drawFence == nullptr || drawFence->get() < 0; + if (requireSync) { + ATRACE_BEGIN("Submit(sync=true)"); + } else { + ATRACE_BEGIN("Submit(sync=false)"); + } + bool success = mGrContext->submit(requireSync); + ATRACE_END(); + if (!success) { + ALOGE("Failed to flush RenderEngine commands"); + // Chances are, something illegal happened (either the caller passed + // us bad parameters, or we messed up our shader generation). + return INVALID_OPERATION; + } + + // checkErrors(); + return NO_ERROR; +} + +size_t SkiaGLRenderEngine::getMaxTextureSize() const { + return mGrContext->maxTextureSize(); +} + +size_t SkiaGLRenderEngine::getMaxViewportDims() const { + return mGrContext->maxRenderTargetSize(); +} + +EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config, + EGLContext shareContext, bool useContextPriority, + Protection protection) { + EGLint renderableType = 0; + if (config == EGL_NO_CONFIG_KHR) { + renderableType = EGL_OPENGL_ES3_BIT; + } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) { + LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE"); + } + EGLint contextClientVersion = 0; + if (renderableType & EGL_OPENGL_ES3_BIT) { + contextClientVersion = 3; + } else if (renderableType & EGL_OPENGL_ES2_BIT) { + contextClientVersion = 2; + } else if (renderableType & EGL_OPENGL_ES_BIT) { + contextClientVersion = 1; + } else { + LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs"); + } + + std::vector contextAttributes; + contextAttributes.reserve(7); + contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION); + contextAttributes.push_back(contextClientVersion); + if (useContextPriority) { + contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG); + contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG); + } + if (protection == Protection::PROTECTED) { + contextAttributes.push_back(EGL_PROTECTED_CONTENT_EXT); + contextAttributes.push_back(EGL_TRUE); + } + contextAttributes.push_back(EGL_NONE); + + EGLContext context = eglCreateContext(display, config, shareContext, contextAttributes.data()); + + if (contextClientVersion == 3 && context == EGL_NO_CONTEXT) { + // eglGetConfigAttrib indicated we can create GLES 3 context, but we failed, thus + // EGL_NO_CONTEXT so that we can abort. + if (config != EGL_NO_CONFIG_KHR) { + return context; + } + // If |config| is EGL_NO_CONFIG_KHR, we speculatively try to create GLES 3 context, so we + // should try to fall back to GLES 2. + contextAttributes[1] = 2; + context = eglCreateContext(display, config, shareContext, contextAttributes.data()); + } + + return context; +} + +EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay display, + EGLConfig config, int hwcFormat, + Protection protection) { + EGLConfig placeholderConfig = config; + if (placeholderConfig == EGL_NO_CONFIG_KHR) { + placeholderConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); + } + std::vector attributes; + attributes.reserve(7); + attributes.push_back(EGL_WIDTH); + attributes.push_back(1); + attributes.push_back(EGL_HEIGHT); + attributes.push_back(1); + if (protection == Protection::PROTECTED) { + attributes.push_back(EGL_PROTECTED_CONTENT_EXT); + attributes.push_back(EGL_TRUE); + } + attributes.push_back(EGL_NONE); + + return eglCreatePbufferSurface(display, placeholderConfig, attributes.data()); +} + +void SkiaGLRenderEngine::cleanFramebufferCache() { + mSurfaceCache.clear(); +} + +} // namespace skia +} // namespace renderengine +} // namespace android \ No newline at end of file diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h new file mode 100644 index 0000000000..eb098cb0ac --- /dev/null +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -0,0 +1,93 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SF_SKIAGLRENDERENGINE_H_ +#define SF_SKIAGLRENDERENGINE_H_ + +#include +#include +#include + +#include +#include + +#include +#include + +#include "SkiaRenderEngine.h" + +namespace android { +namespace renderengine { +namespace skia { + +class SkiaGLRenderEngine : public skia::SkiaRenderEngine { +public: + static std::unique_ptr create(const RenderEngineCreationArgs& args); + SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLConfig config, + EGLContext ctxt, EGLSurface placeholder, EGLContext protectedContext, + EGLSurface protectedPlaceholder); + ~SkiaGLRenderEngine() override{}; + + void unbindExternalTextureBuffer(uint64_t bufferId) override; + status_t drawLayers(const DisplaySettings& display, + const std::vector& layers, + const sp& buffer, const bool useFramebufferCache, + base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; + void cleanFramebufferCache() override; + +protected: + void dump(std::string& /*result*/) override{}; + size_t getMaxTextureSize() const override; + size_t getMaxViewportDims() const override; + +private: + static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); + static EGLContext createEglContext(EGLDisplay display, EGLConfig config, + EGLContext shareContext, bool useContextPriority, + Protection protection); + static EGLSurface createPlaceholderEglPbufferSurface(EGLDisplay display, EGLConfig config, + int hwcFormat, Protection protection); + + base::unique_fd flush(); + bool waitFence(base::unique_fd fenceFd); + + EGLDisplay mEGLDisplay; + EGLConfig mEGLConfig; + EGLContext mEGLContext; + EGLSurface mPlaceholderSurface; + EGLContext mProtectedEGLContext; + EGLSurface mProtectedPlaceholderSurface; + + // Cache of GL images that we'll store per GraphicBuffer ID + std::unordered_map> mImageCache GUARDED_BY(mRenderingMutex); + // Mutex guarding rendering operations, so that: + // 1. GL operations aren't interleaved, and + // 2. Internal state related to rendering that is potentially modified by + // multiple threads is guaranteed thread-safe. + std::mutex mRenderingMutex; + + sp mLastDrawFence; + + sk_sp mGrContext; + + std::unordered_map> mSurfaceCache; +}; + +} // namespace skia +} // namespace renderengine +} // namespace android + +#endif /* SF_GLESRENDERENGINE_H_ */ \ No newline at end of file diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp new file mode 100644 index 0000000000..81f0b6f970 --- /dev/null +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -0,0 +1,26 @@ +/* + * Copyright 2020 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 "RenderEngine" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +namespace android { +namespace renderengine { +namespace skia {} // namespace skia +} // namespace renderengine +} // namespace android \ No newline at end of file diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h new file mode 100644 index 0000000000..3c5d0cf24d --- /dev/null +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -0,0 +1,71 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SF_SKIARENDERENGINE_H_ +#define SF_SKIARENDERENGINE_H_ + +#include +#include + +namespace android { + +namespace renderengine { + +class Mesh; +class Texture; + +namespace skia { + +class BlurFilter; + +// TODO: Put common skia stuff here that can be shared between the GL & Vulkan backends +// Currently mostly just handles all the no-op / missing APIs +class SkiaRenderEngine : public impl::RenderEngine { +public: + static std::unique_ptr create(const RenderEngineCreationArgs& args); + SkiaRenderEngine(const RenderEngineCreationArgs& args) : RenderEngine(args){}; + ~SkiaRenderEngine() override {} + + virtual void primeCache() const override{}; + virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override{}; + virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{}; + virtual status_t bindExternalTextureBuffer(uint32_t /*texName*/, + const sp& /*buffer*/, + const sp& /*fence*/) { + return 0; + }; // EXCLUDES(mRenderingMutex); + virtual void cacheExternalTextureBuffer(const sp& /*buffer*/){}; + virtual void unbindExternalTextureBuffer(uint64_t /*bufferId*/){}; + + virtual bool isProtected() const override { return false; } // mInProtectedContext; } + virtual bool supportsProtectedContent() const override { return false; }; + virtual bool useProtectedContext(bool /*useProtectedContext*/) override { return false; }; + virtual status_t drawLayers(const DisplaySettings& /*display*/, + const std::vector& /*layers*/, + const sp& /*buffer*/, + const bool /*useFramebufferCache*/, + base::unique_fd&& /*bufferFence*/, + base::unique_fd* /*drawFence*/) override { + return 0; + }; + virtual bool cleanupPostRender(CleanupMode) override { return true; }; +}; + +} // namespace skia +} // namespace renderengine +} // namespace android + +#endif /* SF_GLESRENDERENGINE_H_ */ \ No newline at end of file diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index b017ad7e78..db808e0663 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -13,7 +13,10 @@ cc_defaults { cc_defaults { name: "libsurfaceflinger_defaults", - defaults: ["surfaceflinger_defaults"], + defaults: [ + "surfaceflinger_defaults", + "skia_deps", + ], cflags: [ "-DLOG_TAG=\"SurfaceFlinger\"", "-DGL_GLEXT_PROTOTYPES", diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 2773fd3a16..8d1ffe326d 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -42,6 +42,9 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" +// Uncomment to enable RE-SK workarounds; b/b/168499446 +//#define USE_SKIA_WORKAROUNDS + namespace android::compositionengine { RenderSurface::~RenderSurface() = default; @@ -81,7 +84,11 @@ void RenderSurface::initialize() { ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status); status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status); +#ifdef USE_SKIA_WORKAROUNDS + status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE); +#else status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER); +#endif ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status); } @@ -113,6 +120,9 @@ void RenderSurface::setProtected(bool useProtected) { if (useProtected) { usageFlags |= GRALLOC_USAGE_PROTECTED; } +#ifdef USE_SKIA_WORKAROUNDS + usageFlags |= GRALLOC_USAGE_HW_TEXTURE; +#endif const int status = native_window_set_usage(mNativeWindow.get(), usageFlags); ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status); if (status == NO_ERROR) { diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index a2fc6925b8..890945f6f3 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -441,7 +441,8 @@ void RegionSamplingThread::captureSample() { mCachedBuffer->getHeight() == sampledBounds.getHeight()) { buffer = mCachedBuffer; } else { - const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER; + const uint32_t usage = + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); } -- cgit v1.2.3-59-g8ed1b From db3dfeec384fa68ebab817224e94bc6b9976ea46 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 17 Nov 2020 17:07:12 -0800 Subject: SurfaceFlinger: add thread name to OneShotTimer Test: interact with device and observe systraces Bug: 170665374 Change-Id: I55af2ec268dfaa10c570876aeeb63e602ec08ef7 --- .../DisplayHardware/PowerAdvisor.cpp | 2 +- services/surfaceflinger/RegionSamplingThread.cpp | 1 + services/surfaceflinger/Scheduler/OneShotTimer.cpp | 12 ++++++++-- services/surfaceflinger/Scheduler/OneShotTimer.h | 5 ++++- services/surfaceflinger/Scheduler/Scheduler.cpp | 6 ++--- .../tests/unittests/OneShotTimerTest.cpp | 26 ++++++++++++++-------- .../tests/unittests/TestableScheduler.h | 2 +- 7 files changed, 37 insertions(+), 17 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index 4b4c050f8e..901e19a6a2 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -64,7 +64,7 @@ int32_t getUpdateTimeout() { PowerAdvisor::PowerAdvisor() : mUseUpdateImminentTimer(getUpdateTimeout() > 0), mUpdateImminentTimer( - OneShotTimer::Interval(getUpdateTimeout()), + "UpdateImminentTimer", OneShotTimer::Interval(getUpdateTimeout()), /* resetCallback */ [this] { mSendUpdateImminent.store(false); }, /* timeoutCallback */ [this] { mSendUpdateImminent.store(true); }) { if (mUseUpdateImminentTimer) { diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index b7b7e4658e..2511eb37b3 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -175,6 +175,7 @@ RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& s mScheduler(scheduler), mTunables(tunables), mIdleTimer( + "RegionSamplingIdleTimer", std::chrono::duration_cast( mTunables.mSamplingTimerTimeout), [] {}, [this] { checkForStaleLuma(); }), diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp index 8e807d6c76..ce3b0c6cfa 100644 --- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp +++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp @@ -40,9 +40,13 @@ void calculateTimeoutTime(std::chrono::nanoseconds timestamp, timespec* spec) { namespace android { namespace scheduler { -OneShotTimer::OneShotTimer(const Interval& interval, const ResetCallback& resetCallback, +OneShotTimer::OneShotTimer(std::string name, const Interval& interval, + const ResetCallback& resetCallback, const TimeoutCallback& timeoutCallback) - : mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {} + : mName(std::move(name)), + mInterval(interval), + mResetCallback(resetCallback), + mTimeoutCallback(timeoutCallback) {} OneShotTimer::~OneShotTimer() { stop(); @@ -71,6 +75,10 @@ void OneShotTimer::stop() { } void OneShotTimer::loop() { + if (pthread_setname_np(pthread_self(), mName.c_str())) { + ALOGW("Failed to set thread name on dispatch thread"); + } + TimerState state = TimerState::RESET; while (true) { bool triggerReset = false; diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h index 8bbd4f5983..3690ce7542 100644 --- a/services/surfaceflinger/Scheduler/OneShotTimer.h +++ b/services/surfaceflinger/Scheduler/OneShotTimer.h @@ -36,7 +36,7 @@ public: using ResetCallback = std::function; using TimeoutCallback = std::function; - OneShotTimer(const Interval& interval, const ResetCallback& resetCallback, + OneShotTimer(std::string name, const Interval& interval, const ResetCallback& resetCallback, const TimeoutCallback& timeoutCallback); ~OneShotTimer(); @@ -81,6 +81,9 @@ private: // Semaphore to keep mThread synchronized. sem_t mSemaphore; + // Timer's name. + std::string mName; + // Interval after which timer expires. const Interval mInterval; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index a14019eeb5..37066317ce 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -135,7 +135,7 @@ Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCal const auto callback = mOptions.supportKernelTimer ? &Scheduler::kernelIdleTimerCallback : &Scheduler::idleTimerCallback; mIdleTimer.emplace( - std::chrono::milliseconds(millis), + "IdleTimer", std::chrono::milliseconds(millis), [this, callback] { std::invoke(callback, this, TimerState::Reset); }, [this, callback] { std::invoke(callback, this, TimerState::Expired); }); mIdleTimer->start(); @@ -144,7 +144,7 @@ Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCal if (const int64_t millis = set_touch_timer_ms(0); millis > 0) { // Touch events are coming to SF every 100ms, so the timer needs to be higher than that mTouchTimer.emplace( - std::chrono::milliseconds(millis), + "TouchTimer", std::chrono::milliseconds(millis), [this] { touchTimerCallback(TimerState::Reset); }, [this] { touchTimerCallback(TimerState::Expired); }); mTouchTimer->start(); @@ -152,7 +152,7 @@ Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCal if (const int64_t millis = set_display_power_timer_ms(0); millis > 0) { mDisplayPowerTimer.emplace( - std::chrono::milliseconds(millis), + "DisplayPowerTimer", std::chrono::milliseconds(millis), [this] { displayPowerTimerCallback(TimerState::Reset); }, [this] { displayPowerTimerCallback(TimerState::Expired); }); mDisplayPowerTimer->start(); diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp index 0208728026..cfbb3f5e9f 100644 --- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp +++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp @@ -57,11 +57,12 @@ protected: namespace { TEST_F(OneShotTimerTest, createAndDestroyTest) { mIdleTimer = std::make_unique( - 3ms, [] {}, [] {}); + "TestTimer", 3ms, [] {}, [] {}); } TEST_F(OneShotTimerTest, startStopTest) { - mIdleTimer = std::make_unique(30ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique("TestTimer", 30ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); auto startTime = std::chrono::steady_clock::now(); mIdleTimer->start(); @@ -81,7 +82,8 @@ TEST_F(OneShotTimerTest, startStopTest) { } TEST_F(OneShotTimerTest, resetTest) { - mIdleTimer = std::make_unique(20ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique("TestTimer", 20ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -106,7 +108,8 @@ TEST_F(OneShotTimerTest, resetTest) { } TEST_F(OneShotTimerTest, resetBackToBackTest) { - mIdleTimer = std::make_unique(20ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique("TestTimer", 20ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -137,7 +140,8 @@ TEST_F(OneShotTimerTest, resetBackToBackTest) { } TEST_F(OneShotTimerTest, startNotCalledTest) { - mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique("TestTimer", 3ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); // The start hasn't happened, so the callback does not happen. EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value()); @@ -149,7 +153,8 @@ TEST_F(OneShotTimerTest, startNotCalledTest) { } TEST_F(OneShotTimerTest, idleTimerIdlesTest) { - mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique("TestTimer", 3ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -169,7 +174,8 @@ TEST_F(OneShotTimerTest, idleTimerIdlesTest) { } TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) { - mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique("TestTimer", 3ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -178,7 +184,8 @@ TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) { } TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) { - mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique("TestTimer", 3ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -192,7 +199,8 @@ TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) { } TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) { - mIdleTimer = std::make_unique(3ms, mResetTimerCallback.getInvocable(), + mIdleTimer = std::make_unique("TestTimer", 3ms, + mResetTimerCallback.getInvocable(), mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index a9d9dc08ad..1b6e9ed514 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -83,7 +83,7 @@ public: mTouchTimer.reset(); } mTouchTimer.emplace( - std::chrono::milliseconds(millis), + "Testable Touch timer", std::chrono::milliseconds(millis), [this] { touchTimerCallback(TimerState::Reset); }, [this] { touchTimerCallback(TimerState::Expired); }); mTouchTimer->start(); -- cgit v1.2.3-59-g8ed1b From 4e2b71fe7792843fc23e13d0201b59377888c3c5 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 10 Nov 2020 15:05:32 -0800 Subject: FTL: Import std::future utilities from SF Now including docs and expanded tests. Bug: 160012986 Test: ftl_test Change-Id: If9eb25646bb33ebc417ea87e6718b46fe0b87cf3 --- include/ftl/future.h | 109 +++++++++++++++++++++ libs/ftl/Android.bp | 1 + libs/ftl/future_test.cpp | 105 ++++++++++++++++++++ services/surfaceflinger/DisplayHardware/HWC2.cpp | 9 +- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 6 +- services/surfaceflinger/Promise.h | 80 --------------- services/surfaceflinger/RegionSamplingThread.cpp | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 15 ++- services/surfaceflinger/tests/unittests/Android.bp | 1 - .../surfaceflinger/tests/unittests/PromiseTest.cpp | 88 ----------------- 10 files changed, 231 insertions(+), 187 deletions(-) create mode 100644 include/ftl/future.h create mode 100644 libs/ftl/future_test.cpp delete mode 100644 services/surfaceflinger/Promise.h delete mode 100644 services/surfaceflinger/tests/unittests/PromiseTest.cpp (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/include/ftl/future.h b/include/ftl/future.h new file mode 100644 index 0000000000..dd6358fa7d --- /dev/null +++ b/include/ftl/future.h @@ -0,0 +1,109 @@ +/* + * Copyright 2020 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 +#include +#include + +namespace android::ftl { + +// Creates a future that defers a function call until its result is queried. +// +// auto future = ftl::defer([](int x) { return x + 1; }, 99); +// assert(future.get() == 100); +// +template +inline auto defer(F&& f, Args&&... args) { + return std::async(std::launch::deferred, std::forward(f), std::forward(args)...); +} + +// Creates a future that wraps a value. +// +// auto future = ftl::yield(42); +// assert(future.get() == 42); +// +// auto ptr = std::make_unique('!'); +// auto future = ftl::yield(std::move(ptr)); +// assert(*future.get() == '!'); +// +template +inline std::future yield(T&& v) { + return defer([](T&& v) { return std::forward(v); }, std::forward(v)); +} + +namespace details { + +template +struct future_result { + using type = T; +}; + +template +struct future_result> { + using type = T; +}; + +template +using future_result_t = typename future_result::type; + +// Attaches a continuation to a future. The continuation is a function that maps T to either R or +// std::future. In the former case, the chain wraps the result in a future as if by ftl::yield. +// +// auto future = ftl::yield(123); +// std::future futures[] = {ftl::yield('a'), ftl::yield('b')}; +// +// std::future chain = +// ftl::chain(std::move(future)) +// .then([](int x) { return static_cast(x % 2); }) +// .then([&futures](std::size_t i) { return std::move(futures[i]); }); +// +// assert(chain.get() == 'b'); +// +template +struct Chain { + // Implicit conversion. + Chain(std::future&& f) : future(std::move(f)) {} + operator std::future&&() && { return std::move(future); } + + T get() && { return future.get(); } + + template > + auto then(F&& op) && -> Chain> { + return defer( + [](auto&& f, F&& op) { + R r = op(f.get()); + if constexpr (std::is_same_v>) { + return r; + } else { + return r.get(); + } + }, + std::move(future), std::forward(op)); + } + + std::future future; +}; + +} // namespace details + +template +inline auto chain(std::future&& f) -> details::Chain { + return std::move(f); +} + +} // namespace android::ftl diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 883d1388d1..5bccaca42d 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -5,6 +5,7 @@ cc_test { address: true, }, srcs: [ + "future_test.cpp", "small_map_test.cpp", "small_vector_test.cpp", "static_vector_test.cpp", diff --git a/libs/ftl/future_test.cpp b/libs/ftl/future_test.cpp new file mode 100644 index 0000000000..9b3e93683f --- /dev/null +++ b/libs/ftl/future_test.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include + +namespace android::test { + +// Keep in sync with example usage in header file. +TEST(Future, Example) { + { + auto future = ftl::defer([](int x) { return x + 1; }, 99); + EXPECT_EQ(future.get(), 100); + } + { + auto future = ftl::yield(42); + EXPECT_EQ(future.get(), 42); + } + { + auto ptr = std::make_unique('!'); + auto future = ftl::yield(std::move(ptr)); + EXPECT_EQ(*future.get(), '!'); + } + { + auto future = ftl::yield(123); + std::future futures[] = {ftl::yield('a'), ftl::yield('b')}; + + std::future chain = ftl::chain(std::move(future)) + .then([](int x) { return static_cast(x % 2); }) + .then([&futures](size_t i) { return std::move(futures[i]); }); + + EXPECT_EQ(chain.get(), 'b'); + } +} + +namespace { + +using ByteVector = std::vector; + +ByteVector decrement(ByteVector bytes) { + std::transform(bytes.begin(), bytes.end(), bytes.begin(), [](auto b) { return b - 1; }); + return bytes; +} + +} // namespace + +TEST(Future, Chain) { + std::packaged_task fetch_string([] { return "ifmmp-"; }); + + std::packaged_task append_string([](std::string str) { + str += "!xpsme"; + return ByteVector{str.begin(), str.end()}; + }); + + std::packaged_task(ByteVector)> decrement_bytes( + [](ByteVector bytes) { return ftl::defer(decrement, std::move(bytes)); }); + + auto fetch = fetch_string.get_future(); + std::thread fetch_thread(std::move(fetch_string)); + + std::thread append_thread, decrement_thread; + + EXPECT_EQ( + "hello, world", + ftl::chain(std::move(fetch)) + .then([](const char* str) { return std::string(str); }) + .then([&](std::string str) { + auto append = append_string.get_future(); + append_thread = std::thread(std::move(append_string), std::move(str)); + return append; + }) + .then([&](ByteVector bytes) { + auto decrement = decrement_bytes.get_future(); + decrement_thread = std::thread(std::move(decrement_bytes), std::move(bytes)); + return decrement; + }) + .then([](std::future bytes) { return bytes; }) + .then([](const ByteVector& bytes) { return std::string(bytes.begin(), bytes.end()); }) + .get()); + + fetch_thread.join(); + append_thread.join(); + decrement_thread.join(); +} + +} // namespace android::test diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index e6bff04601..426092dc11 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -26,18 +26,17 @@ #include "HWC2.h" +#include +#include #include #include #include -#include - -#include #include +#include #include #include -#include "../Promise.h" #include "ComposerHal.h" namespace android { @@ -647,7 +646,7 @@ Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests } std::future Display::setDisplayBrightness(float brightness) { - return promise::defer([composer = &mComposer, id = mId, brightness] { + return ftl::defer([composer = &mComposer, id = mId, brightness] { const auto intError = composer->setDisplayBrightness(id, brightness); return static_cast(intError); }); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 1548d18652..5fa72b83fc 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,6 @@ #include #include "../Layer.h" // needed only for debugging -#include "../Promise.h" #include "../SurfaceFlinger.h" #include "../SurfaceFlingerProperties.h" #include "ComposerHal.h" @@ -792,10 +792,10 @@ status_t HWComposer::getDisplayedContentSample(HalDisplayId displayId, uint64_t std::future HWComposer::setDisplayBrightness(PhysicalDisplayId displayId, float brightness) { - RETURN_IF_INVALID_DISPLAY(displayId, promise::yield(BAD_INDEX)); + RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield(BAD_INDEX)); auto& display = mDisplayData[displayId].hwcDisplay; - return promise::chain(display->setDisplayBrightness(brightness)) + return ftl::chain(display->setDisplayBrightness(brightness)) .then([displayId](hal::Error error) -> status_t { if (error == hal::Error::UNSUPPORTED) { RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); diff --git a/services/surfaceflinger/Promise.h b/services/surfaceflinger/Promise.h deleted file mode 100644 index a80d441a4b..0000000000 --- a/services/surfaceflinger/Promise.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2020 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 -#include -#include - -namespace android::promise { -namespace impl { - -template -struct FutureResult { - using Type = T; -}; - -template -struct FutureResult> { - using Type = T; -}; - -} // namespace impl - -template -using FutureResult = typename impl::FutureResult::Type; - -template -inline auto defer(Args... args) { - return std::async(std::launch::deferred, std::forward(args)...); -} - -template -inline std::future yield(T&& v) { - return defer([](T&& v) { return std::forward(v); }, std::forward(v)); -} - -template -struct Chain { - Chain(std::future&& f) : future(std::move(f)) {} - operator std::future&&() && { return std::move(future); } - - T get() && { return future.get(); } - - template > - auto then(F&& op) && -> Chain> { - return defer( - [](auto&& f, F&& op) { - R r = op(f.get()); - if constexpr (std::is_same_v>) { - return r; - } else { - return r.get(); - } - }, - std::move(future), std::forward(op)); - } - - std::future future; -}; - -template -inline Chain chain(std::future&& f) { - return std::move(f); -} - -} // namespace android::promise diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 2511eb37b3..ad4877bdeb 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -38,7 +39,6 @@ #include "DisplayDevice.h" #include "DisplayRenderArea.h" #include "Layer.h" -#include "Promise.h" #include "Scheduler/VsyncController.h" #include "SurfaceFlinger.h" @@ -389,7 +389,7 @@ void RegionSamplingThread::captureSample() { const Rect sampledBounds = sampleRegion.bounds(); - SurfaceFlinger::RenderAreaFuture renderAreaFuture = promise::defer([=] { + SurfaceFlinger::RenderAreaFuture renderAreaFuture = ftl::defer([=] { return DisplayRenderArea::create(displayWeak, screencapRegion.bounds(), sampledBounds.getSize(), ui::Dataspace::V0_SRGB, orientation); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2fb362611f..f067922af3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -47,8 +47,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -81,6 +80,7 @@ #include #include +#include #include #include #include @@ -112,7 +112,6 @@ #include "LayerVector.h" #include "MonitoredProducer.h" #include "NativeWindowSurface.h" -#include "Promise.h" #include "RefreshRateOverlay.h" #include "RegionSamplingThread.h" #include "Scheduler/DispSyncSource.h" @@ -1502,12 +1501,12 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, f return BAD_VALUE; } - return promise::chain(schedule([=]() MAIN_THREAD { + return ftl::chain(schedule([=]() MAIN_THREAD { if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { return getHwComposer().setDisplayBrightness(*displayId, brightness); } else { ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); - return promise::yield(NAME_NOT_FOUND); + return ftl::yield(NAME_NOT_FOUND); } })) .then([](std::future task) { return task; }) @@ -5484,7 +5483,7 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, } } - RenderAreaFuture renderAreaFuture = promise::defer([=] { + RenderAreaFuture renderAreaFuture = ftl::defer([=] { return DisplayRenderArea::create(displayWeak, args.sourceCrop, reqSize, dataspace, args.useIdentityTransform, args.captureSecureLayers); }); @@ -5518,7 +5517,7 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode); } - RenderAreaFuture renderAreaFuture = promise::defer([=] { + RenderAreaFuture renderAreaFuture = ftl::defer([=] { return DisplayRenderArea::create(displayWeak, Rect(), size, dataspace, false /* useIdentityTransform */, false /* captureSecureLayers */); @@ -5622,7 +5621,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, } bool childrenOnly = args.childrenOnly; - RenderAreaFuture renderAreaFuture = promise::defer([=]() -> std::unique_ptr { + RenderAreaFuture renderAreaFuture = ftl::defer([=]() -> std::unique_ptr { return std::make_unique(*this, parent, crop, reqSize, dataspace, childrenOnly, layerStackSpaceRect, captureSecureLayers); diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 871222c8b0..20f8f4212d 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -50,7 +50,6 @@ cc_test { "LayerHistoryTest.cpp", "LayerMetadataTest.cpp", "MessageQueueTest.cpp", - "PromiseTest.cpp", "SurfaceFlinger_CreateDisplayTest.cpp", "SurfaceFlinger_DestroyDisplayTest.cpp", "SurfaceFlinger_GetDisplayNativePrimariesTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/PromiseTest.cpp b/services/surfaceflinger/tests/unittests/PromiseTest.cpp deleted file mode 100644 index e4dc1fedb1..0000000000 --- a/services/surfaceflinger/tests/unittests/PromiseTest.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include - -#include - -#include "Promise.h" - -namespace android { -namespace { - -using Bytes = std::vector; - -Bytes decrement(Bytes bytes) { - std::transform(bytes.begin(), bytes.end(), bytes.begin(), [](auto b) { return b - 1; }); - return bytes; -} - -} // namespace - -TEST(PromiseTest, yield) { - EXPECT_EQ(42, promise::yield(42).get()); - - auto ptr = std::make_unique('!'); - auto future = promise::yield(std::move(ptr)); - EXPECT_EQ('!', *future.get()); -} - -TEST(PromiseTest, chain) { - std::packaged_task fetchString([] { return "ifmmp-"; }); - - std::packaged_task appendString([](std::string str) { - str += "!xpsme"; - return Bytes{str.begin(), str.end()}; - }); - - std::packaged_task(Bytes)> decrementBytes( - [](Bytes bytes) { return promise::defer(decrement, std::move(bytes)); }); - - auto fetch = fetchString.get_future(); - std::thread fetchThread(std::move(fetchString)); - - std::thread appendThread, decrementThread; - - EXPECT_EQ("hello, world", - promise::chain(std::move(fetch)) - .then([](const char* str) { return std::string(str); }) - .then([&](std::string str) { - auto append = appendString.get_future(); - appendThread = std::thread(std::move(appendString), std::move(str)); - return append; - }) - .then([&](Bytes bytes) { - auto decrement = decrementBytes.get_future(); - decrementThread = std::thread(std::move(decrementBytes), - std::move(bytes)); - return decrement; - }) - .then([](std::future bytes) { return bytes; }) - .then([](const Bytes& bytes) { - return std::string(bytes.begin(), bytes.end()); - }) - .get()); - - fetchThread.join(); - appendThread.join(); - decrementThread.join(); -} - -} // namespace android -- cgit v1.2.3-59-g8ed1b From bed7fd3566605ea21f55d99f0d0708a0f584d885 Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Mon, 21 Dec 2020 20:02:20 +0100 Subject: SF: Compile with -Wextra Compile with -Wextra for additional conversion checks. In each file which produces compile errors -Wextra is ignored. Bug: 175126758 Test: m surfaceflinger && m libsurfaceflinger_unittest Change-Id: Iec6bcc699715a99c8c65d891ab3c0481e884c728 --- libs/renderengine/tests/RenderEngineTest.cpp | 3 ++- services/surfaceflinger/Android.bp | 1 + services/surfaceflinger/BufferQueueLayer.cpp | 3 ++- services/surfaceflinger/BufferStateLayer.cpp | 3 ++- .../include/compositionengine/DisplayColorProfile.h | 3 ++- .../include/compositionengine/DisplayColorProfileCreationArgs.h | 3 ++- .../CompositionEngine/include/compositionengine/LayerFE.h | 3 ++- .../include/compositionengine/LayerFECompositionState.h | 3 ++- .../CompositionEngine/include/compositionengine/OutputLayer.h | 3 ++- .../include/compositionengine/impl/HwcBufferCache.h | 3 ++- .../include/compositionengine/impl/OutputCompositionState.h | 3 ++- .../include/compositionengine/impl/OutputLayerCompositionState.h | 3 ++- services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp | 7 +++++++ services/surfaceflinger/CompositionEngine/tests/MockHWC2.h | 3 ++- services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h | 3 ++- .../surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp | 7 +++++++ services/surfaceflinger/DisplayHardware/ComposerHal.h | 3 ++- services/surfaceflinger/DisplayHardware/HWComposer.h | 3 ++- services/surfaceflinger/LayerProtoHelper.cpp | 3 ++- services/surfaceflinger/RefreshRateOverlay.cpp | 3 ++- services/surfaceflinger/RegionSamplingThread.cpp | 3 ++- services/surfaceflinger/Scheduler/LayerInfo.cpp | 7 +++++++ services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp | 7 +++++++ services/surfaceflinger/Scheduler/Scheduler.h | 3 ++- services/surfaceflinger/Scheduler/VSyncPredictor.cpp | 6 ++++++ services/surfaceflinger/SurfaceFlinger.cpp | 3 ++- services/surfaceflinger/TimeStats/TimeStats.h | 3 ++- services/surfaceflinger/tests/DetachChildren_test.cpp | 5 ++++- services/surfaceflinger/tests/DisplayConfigs_test.cpp | 7 +++++++ services/surfaceflinger/tests/InvalidHandles_test.cpp | 3 +++ services/surfaceflinger/tests/LayerTransactionTest.h | 3 ++- services/surfaceflinger/tests/ScreenCapture_test.cpp | 3 +++ services/surfaceflinger/tests/SurfaceInterceptor_test.cpp | 3 ++- services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp | 3 ++- services/surfaceflinger/tests/unittests/CachingTest.cpp | 3 ++- services/surfaceflinger/tests/unittests/CompositionTest.cpp | 3 ++- services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp | 7 +++++++ .../surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp | 7 +++++++ .../surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h | 3 ++- services/surfaceflinger/tests/unittests/EventThreadTest.cpp | 7 +++++++ services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp | 7 +++++++ services/surfaceflinger/tests/unittests/FrameTracerTest.cpp | 3 ++- services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp | 7 +++++++ services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp | 7 +++++++ services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp | 7 +++++++ services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp | 7 +++++++ services/surfaceflinger/tests/unittests/TimeStatsTest.cpp | 3 ++- .../surfaceflinger/tests/unittests/TransactionApplicationTest.cpp | 3 ++- .../surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp | 3 ++- services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp | 3 ++- services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp | 7 +++++++ services/surfaceflinger/tests/utils/TransactionUtils.h | 3 ++- 52 files changed, 181 insertions(+), 34 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index d9dfd8cc8d..47b8cad12d 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -20,6 +20,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include #include @@ -1844,4 +1845,4 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index fdb8aaf483..a7cd2582b7 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -3,6 +3,7 @@ cc_defaults { cflags: [ "-Wall", "-Werror", + "-Wextra", "-Wformat", "-Wthread-safety", "-Wunused", diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index e8e31db236..04cec4fafe 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #undef LOG_TAG #define LOG_TAG "BufferQueueLayer" @@ -661,4 +662,4 @@ void BufferQueueLayer::ContentsChangedListener::abandon() { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 7ec7f36548..bca1c69c0f 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" //#define LOG_NDEBUG 0 #undef LOG_TAG @@ -870,4 +871,4 @@ uint32_t BufferStateLayer::doTransaction(uint32_t flags) { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h index 67e6deb506..df44e75625 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h @@ -22,11 +22,12 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" namespace android { diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h index 7eb8eb136d..1136e3d513 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h @@ -23,11 +23,12 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 26f7f68dfb..018a6875bd 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -23,11 +23,12 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include #include diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 5a3b9ac817..c445d5b615 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -29,6 +29,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include #include @@ -37,7 +38,7 @@ #include "DisplayHardware/Hal.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" namespace android::compositionengine { diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index aa70ef836d..fb19216cc9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -25,12 +25,13 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include "DisplayHardware/ComposerHal.h" #include "DisplayHardware/DisplayIdentification.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" namespace android { diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h index 2864c10fd8..aa049a8f83 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h @@ -22,11 +22,12 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 06e6a6f46d..8f767d37f6 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -23,11 +23,12 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include #include diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index d2b38d1815..9a118d3f3a 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -30,11 +30,12 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include "DisplayHardware/ComposerHal.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" namespace android { diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 1befbf8306..348ec398ae 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #include #include @@ -1043,3 +1047,6 @@ TEST_F(DisplayFunctionalTest, postFramebufferCriticalCallsAreOrdered) { } // namespace } // namespace android::compositionengine + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h index 87911ccacf..95186599fc 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h @@ -27,12 +27,13 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include #include "DisplayHardware/HWC2.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" namespace android { namespace HWC2 { diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index 84c027bfd3..e64a9f1855 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -22,11 +22,12 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include "DisplayHardware/HWComposer.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" namespace android { namespace mock { diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 6ce8a6b2ea..cd39733839 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #include #include @@ -359,3 +363,6 @@ TEST_F(RenderSurfaceTest, flipForwardsSignal) { } // namespace } // namespace android::compositionengine + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 5b66809d53..c756d658a4 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -26,6 +26,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include #include @@ -38,7 +39,7 @@ #include // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" namespace android { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index d8af5bf449..50c98530aa 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -32,8 +32,9 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include -#pragma clang diagnostic pop +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include #include diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index 59fad9bf0f..b1db6d34a3 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include "LayerProtoHelper.h" @@ -173,4 +174,4 @@ void LayerProtoHelper::writeToProto(const mat4 matrix, ColorTransformProto* colo } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index c291b7f2e0..6a511a85a0 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include @@ -262,4 +263,4 @@ void RefreshRateOverlay::reset() { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index ad4877bdeb..f450ea5f2f 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" //#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -501,4 +502,4 @@ void RegionSamplingThread::threadMain() NO_THREAD_SAFETY_ANALYSIS { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 1c0065c9ad..b0dffd1846 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + // #define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -298,3 +302,6 @@ bool LayerInfo::RefreshRateHistory::isConsistent() const { } } // namespace android::scheduler + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index cd03c180c0..200701209b 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -17,6 +17,10 @@ // #define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #include "RefreshRateConfigs.h" #include #include @@ -791,3 +795,6 @@ void RefreshRateConfigs::dump(std::string& result) const { } } // namespace android::scheduler + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 052c425e76..5a09b1f114 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -26,8 +26,9 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include -#pragma clang diagnostic pop +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include "EventThread.h" #include "LayerHistory.h" diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index a6f9372a5c..7cca206357 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 #include "VSyncPredictor.h" @@ -339,3 +343,5 @@ void VSyncPredictor::dump(std::string& result) const { } // namespace android::scheduler +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 68d2a68322..57e02f183c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" //#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -6394,4 +6395,4 @@ int SurfaceFlinger::getGPUContextPriority() { #endif // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index a83b2bfae6..8fac8e9102 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -20,11 +20,12 @@ #include #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include #include diff --git a/services/surfaceflinger/tests/DetachChildren_test.cpp b/services/surfaceflinger/tests/DetachChildren_test.cpp index 9c7b1fcc04..abf8b1a2b9 100644 --- a/services/surfaceflinger/tests/DetachChildren_test.cpp +++ b/services/surfaceflinger/tests/DetachChildren_test.cpp @@ -371,4 +371,7 @@ TEST_F(DetachChildren, ReparentParentLayerOfDetachedChildren) { } } -} // namespace android \ No newline at end of file +} // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" \ No newline at end of file diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp index 3a8b40fd67..55b317382e 100644 --- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp +++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #include #include #include @@ -143,3 +147,6 @@ TEST_F(RefreshRateRangeTest, setAllowGroupSwitching) { } } // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp index 152d2d26f4..58b039e5d5 100644 --- a/services/surfaceflinger/tests/InvalidHandles_test.cpp +++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp @@ -70,3 +70,6 @@ TEST_F(InvalidHandleTest, captureLayersInvalidHandle) { } // namespace } // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" \ No newline at end of file diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index b87c734e27..67585185f9 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -19,6 +19,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include #include @@ -306,4 +307,4 @@ private: } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" \ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index 7df3711183..214a0cd276 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -837,3 +837,6 @@ TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) { } } // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" \ No newline at end of file diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 81e648aaef..8dc9a1212f 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include #include @@ -1043,4 +1044,4 @@ TEST_F(SurfaceInterceptorTest, InterceptSimultaneousUpdatesWorks) { } // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index a24aeba6f0..bd49728215 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" // #define LOG_NDEBUG 0 #undef LOG_TAG @@ -2017,4 +2018,4 @@ int main(int argc, char** argv) { } // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/tests/unittests/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp index 1b8c76d1b9..6bc23188a2 100644 --- a/services/surfaceflinger/tests/unittests/CachingTest.cpp +++ b/services/surfaceflinger/tests/unittests/CachingTest.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #undef LOG_TAG #define LOG_TAG "CachingTest" @@ -97,4 +98,4 @@ TEST_F(SlotGenerationTest, getHwcCacheSlot_Reuse) { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index be9d336137..83e3ba414e 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #undef LOG_TAG #define LOG_TAG "CompositionTest" @@ -1533,4 +1534,4 @@ TEST_F(CompositionTest, DebugOptionForcingClientCompositionOfBufferLayerWithDirt } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp index be7609a1a0..77a3e1449f 100644 --- a/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #include #include @@ -80,3 +84,6 @@ TEST(DisplayIdGeneratorTest, maxIdsCount) { } } // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp index 02ce07904e..dc04b6d91d 100644 --- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #include #include @@ -409,3 +413,6 @@ TEST(DisplayIdentificationTest, getVirtualDisplayId) { } } // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index 01cdb2896f..06c0f8ed30 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -19,6 +19,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include #include "DisplayIdentificationTest.h" @@ -753,4 +754,4 @@ using HwcVirtualDisplayCase = } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index ee56178169..0cd50cee3b 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" @@ -623,3 +627,6 @@ TEST_F(EventThreadTest, requestNextVsyncWithThrottleVsyncDoesntPostVSync) { } // namespace } // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index 4b897fa17c..169698ba70 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #include "gmock/gmock-spec-builders.h" #include "mock/MockTimeStats.h" #undef LOG_TAG @@ -1333,3 +1337,6 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli JankType::AppDeadlineMissed | JankType::BufferStuffing); } } // namespace android::frametimeline + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp index a119e27d41..2c71a2e45a 100644 --- a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" @@ -381,4 +382,4 @@ TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index cbc1e0203a..2ee9c64478 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #undef LOG_TAG #define LOG_TAG "LayerHistoryTest" @@ -754,3 +758,6 @@ INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryTestParameterized, } // namespace } // namespace scheduler } // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp index 75a061bf77..373fd74020 100644 --- a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" @@ -107,3 +111,6 @@ TEST_F(LayerMetadataTest, merge) { } // namespace } // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 29be5aba47..45f0ee6d38 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #undef LOG_TAG #define LOG_TAG "SchedulerUnittests" @@ -1656,3 +1660,6 @@ TEST_F(RefreshRateConfigsTest, populatePreferredFrameRate_twoUids) { } // namespace } // namespace scheduler } // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index e93d0d0805..218840230b 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #undef LOG_TAG #define LOG_TAG "SchedulerUnittests" @@ -216,3 +220,6 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { } // namespace } // namespace scheduler } // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index ace370f283..fb9afd4045 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" @@ -1320,4 +1321,4 @@ TEST_F(TimeStatsTest, canSurviveMonkey) { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index fa6ff301af..06275c6b5b 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #undef LOG_TAG #define LOG_TAG "CompositionTest" @@ -344,4 +345,4 @@ TEST_F(TransactionApplicationTest, FromHandle) { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index 72b5396047..00cf574cb2 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" @@ -1152,4 +1153,4 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, runCallbackWithReadyDuration) { } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp index a1420225ca..a4ddbf46d8 100644 --- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp @@ -17,6 +17,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" @@ -492,4 +493,4 @@ TEST_F(VSyncPredictorTest, InconsistentVsyncValueIsFlushedEventually) { } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index a7568e4293..b9651ea672 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra" + #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" #define LOG_NDEBUG 0 @@ -491,3 +495,6 @@ TEST_F(VSyncReactorTest, periodIsMeasuredIfIgnoringComposer) { } } // namespace android::scheduler + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h index 5c5b18ec1c..3cbfed98f5 100644 --- a/services/surfaceflinger/tests/utils/TransactionUtils.h +++ b/services/surfaceflinger/tests/utils/TransactionUtils.h @@ -18,6 +18,7 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wextra" #include @@ -186,4 +187,4 @@ public: } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" \ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" \ No newline at end of file -- cgit v1.2.3-59-g8ed1b From e90dd52de547df1fcef4b928b356a49c60d3b64d Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 29 Dec 2020 12:08:45 -0800 Subject: SurfaceFlinger: return DisplayStatInfo from getDisplayStatInfo Code cleanup - return the class instead of passing it as an output parameter. Test: SF unit tests Change-Id: I7a995415a81f3944d93a1cb573c8e3108464bd07 --- services/surfaceflinger/RegionSamplingThread.cpp | 3 +-- services/surfaceflinger/Scheduler/Scheduler.cpp | 7 ++++--- services/surfaceflinger/Scheduler/Scheduler.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 14 +++++--------- 4 files changed, 11 insertions(+), 15 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index ad4877bdeb..2aea8b4c74 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -250,8 +250,7 @@ void RegionSamplingThread::doSample() { // If there is relatively little time left for surfaceflinger // until the next vsync deadline, defer this sampling work // to a later frame, when hopefully there will be more time. - DisplayStatInfo stats; - mScheduler.getDisplayStatInfo(&stats, systemTime()); + const DisplayStatInfo stats = mScheduler.getDisplayStatInfo(systemTime()); if (std::chrono::nanoseconds(stats.vsyncTime) - now < timeForRegionSampling) { ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::waitForQuietFrame)); mDiscardedFrames++; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index d032b6d409..18c899bc0f 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -426,9 +426,10 @@ void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds wo thread->setDuration(workDuration, readyDuration); } -void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats, nsecs_t now) { - stats->vsyncTime = mVsyncSchedule.tracker->nextAnticipatedVSyncTimeFrom(now); - stats->vsyncPeriod = mVsyncSchedule.tracker->currentPeriod(); +DisplayStatInfo Scheduler::getDisplayStatInfo(nsecs_t now) { + const auto vsyncTime = mVsyncSchedule.tracker->nextAnticipatedVSyncTimeFrom(now); + const auto vsyncPeriod = mVsyncSchedule.tracker->currentPeriod(); + return DisplayStatInfo{.vsyncTime = vsyncTime, .vsyncPeriod = vsyncPeriod}; } Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index c4e1edf574..403d9bc097 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -101,7 +101,7 @@ public: void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration); - void getDisplayStatInfo(DisplayStatInfo* stats, nsecs_t now); + DisplayStatInfo getDisplayStatInfo(nsecs_t now); // Returns injector handle if injection has toggled, or an invalid handle otherwise. ConnectionHandle enableVSyncInjection(bool enable); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 89442ac728..fd2e20ee92 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -963,7 +963,7 @@ status_t SurfaceFlinger::getDisplayStats(const sp&, DisplayStatInfo* st return BAD_VALUE; } - mScheduler->getDisplayStatInfo(stats, systemTime()); + *stats = mScheduler->getDisplayStatInfo(systemTime()); return NO_ERROR; } @@ -1440,8 +1440,7 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { status_t SurfaceFlinger::injectVSync(nsecs_t when) { Mutex::Autolock lock(mStateLock); - DisplayStatInfo stats; - mScheduler->getDisplayStatInfo(&stats, when); + const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(when); const auto expectedPresent = calculateExpectedPresentTime(stats); return mScheduler->injectVSync(when, /*expectedVSyncTime=*/expectedPresent, /*deadlineTimestamp=*/expectedPresent) @@ -1769,8 +1768,7 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT // Add some slop to correct for drift. This should generally be // smaller than a typical frame duration, but should not be so small // that it reports reasonable drift as a missed frame. - DisplayStatInfo stats; - mScheduler->getDisplayStatInfo(&stats, systemTime()); + const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(systemTime()); const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2; const nsecs_t previousPresentTime = previousFramePresentTime(); const TracedOrdinal frameMissed = {"PrevFrameMissed", @@ -2147,8 +2145,7 @@ void SurfaceFlinger::postComposition() { auto presentFenceTime = std::make_shared(mPreviousPresentFences[0]); getBE().mDisplayTimeline.push(presentFenceTime); - DisplayStatInfo stats; - mScheduler->getDisplayStatInfo(&stats, systemTime()); + const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(systemTime()); // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might // be sampled a little later than when we started doing work for this frame, @@ -3364,8 +3361,7 @@ status_t SurfaceFlinger::setTransactionState( if (!pendingTransactions) { const auto now = systemTime(); const bool nextVsyncPending = now < mExpectedPresentTime.load(); - DisplayStatInfo stats; - mScheduler->getDisplayStatInfo(&stats, now); + const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now); mExpectedPresentTime = calculateExpectedPresentTime(stats); // The transaction might arrive just before the next vsync but after // invalidate was called. In that case we need to get the next vsync -- cgit v1.2.3-59-g8ed1b From 17ac24b6c1252f88ccaf7089fa68bee3e1ef7ed9 Mon Sep 17 00:00:00 2001 From: chaviw Date: Thu, 28 Jan 2021 18:50:05 -0800 Subject: Added new arguments for screenshot request Added frameScaleX and frameScaleY to replace frameScale to allow callers to specify an X and Y scale separately. Added grayscale flag to allow the caller to take the screenshot in grayscale. Test: ScreenCaptureTest.CaptureWithGrayscale Bug: 155825630 Change-Id: Iea043b7074707df897d80bf057d7cc3870afad89 --- libs/gui/LayerState.cpp | 8 ++- libs/gui/include/gui/LayerState.h | 5 +- services/surfaceflinger/RegionSamplingThread.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 59 ++++++++++++---------- services/surfaceflinger/SurfaceFlinger.h | 9 ++-- services/surfaceflinger/tests/LayerState_test.cpp | 16 ++++-- .../surfaceflinger/tests/ScreenCapture_test.cpp | 39 +++++++++++++- .../tests/unittests/TestableSurfaceFlinger.h | 3 +- 8 files changed, 102 insertions(+), 39 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 2946aaed37..ab20725936 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -644,11 +644,13 @@ bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunc status_t CaptureArgs::write(Parcel& output) const { SAFE_PARCEL(output.writeInt32, static_cast(pixelFormat)); SAFE_PARCEL(output.write, sourceCrop); - SAFE_PARCEL(output.writeFloat, frameScale); + SAFE_PARCEL(output.writeFloat, frameScaleX); + SAFE_PARCEL(output.writeFloat, frameScaleY); SAFE_PARCEL(output.writeBool, captureSecureLayers); SAFE_PARCEL(output.writeInt32, uid); SAFE_PARCEL(output.writeInt32, static_cast(dataspace)); SAFE_PARCEL(output.writeBool, allowProtected); + SAFE_PARCEL(output.writeBool, grayscale); return NO_ERROR; } @@ -657,12 +659,14 @@ status_t CaptureArgs::read(const Parcel& input) { SAFE_PARCEL(input.readInt32, &value); pixelFormat = static_cast(value); SAFE_PARCEL(input.read, sourceCrop); - SAFE_PARCEL(input.readFloat, &frameScale); + SAFE_PARCEL(input.readFloat, &frameScaleX); + SAFE_PARCEL(input.readFloat, &frameScaleY); SAFE_PARCEL(input.readBool, &captureSecureLayers); SAFE_PARCEL(input.readInt32, &uid); SAFE_PARCEL(input.readInt32, &value); dataspace = static_cast(value); SAFE_PARCEL(input.readBool, &allowProtected); + SAFE_PARCEL(input.readBool, &grayscale); return NO_ERROR; } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index b1305c6607..f643ab50a0 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -328,7 +328,8 @@ struct CaptureArgs { ui::PixelFormat pixelFormat{ui::PixelFormat::RGBA_8888}; Rect sourceCrop; - float frameScale{1}; + float frameScaleX{1}; + float frameScaleY{1}; bool captureSecureLayers{false}; int32_t uid{UNSET_UID}; // Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured @@ -346,6 +347,8 @@ struct CaptureArgs { // the contents being accessed/captured by screenshot or unsecure display. bool allowProtected = false; + bool grayscale = false; + virtual status_t write(Parcel& output) const; virtual status_t read(const Parcel& input); }; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 19b3d6e1a5..9186538c0a 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -451,7 +451,7 @@ void RegionSamplingThread::captureSample() { const sp captureListener = new SyncScreenCaptureListener(); mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - true /* regionSampling */, captureListener); + true /* regionSampling */, false /* grayscale */, captureListener); ScreenCaptureResults captureResults = captureListener->waitForResults(); std::vector activeDescriptors; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 27df232472..f89b199636 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4900,23 +4900,24 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co result.append("\n"); } -void SurfaceFlinger::updateColorMatrixLocked() { - mat4 colorMatrix; - if (mGlobalSaturationFactor != 1.0f) { - // Rec.709 luma coefficients - float3 luminance{0.213f, 0.715f, 0.072f}; - luminance *= 1.0f - mGlobalSaturationFactor; - mat4 saturationMatrix = mat4( - vec4{luminance.r + mGlobalSaturationFactor, luminance.r, luminance.r, 0.0f}, - vec4{luminance.g, luminance.g + mGlobalSaturationFactor, luminance.g, 0.0f}, - vec4{luminance.b, luminance.b, luminance.b + mGlobalSaturationFactor, 0.0f}, - vec4{0.0f, 0.0f, 0.0f, 1.0f} - ); - colorMatrix = mClientColorMatrix * saturationMatrix * mDaltonizer(); - } else { - colorMatrix = mClientColorMatrix * mDaltonizer(); +mat4 SurfaceFlinger::calculateColorMatrix(float saturation) { + if (saturation == 1) { + return mat4(); } + float3 luminance{0.213f, 0.715f, 0.072f}; + luminance *= 1.0f - saturation; + mat4 saturationMatrix = mat4(vec4{luminance.r + saturation, luminance.r, luminance.r, 0.0f}, + vec4{luminance.g, luminance.g + saturation, luminance.g, 0.0f}, + vec4{luminance.b, luminance.b, luminance.b + saturation, 0.0f}, + vec4{0.0f, 0.0f, 0.0f, 1.0f}); + return saturationMatrix; +} + +void SurfaceFlinger::updateColorMatrixLocked() { + mat4 colorMatrix = + mClientColorMatrix * calculateColorMatrix(mGlobalSaturationFactor) * mDaltonizer(); + if (mCurrentState.colorMatrix != colorMatrix) { mCurrentState.colorMatrix = colorMatrix; mCurrentState.colorMatrixChanged = true; @@ -5628,7 +5629,8 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, }; return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, args.allowProtected, captureListener); + args.pixelFormat, args.allowProtected, args.grayscale, + captureListener); } status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, @@ -5664,7 +5666,7 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, ui::PixelFormat::RGBA_8888, false /* allowProtected */, - captureListener); + false /* grayscale */, captureListener); } status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, @@ -5710,12 +5712,12 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, crop.bottom = parentSourceBounds.getHeight(); } - if (crop.isEmpty() || args.frameScale <= 0.0f) { + if (crop.isEmpty() || args.frameScaleX <= 0.0f || args.frameScaleY <= 0.0f) { // Error out if the layer has no source bounds (i.e. they are boundless) and a source // crop was not specified, or an invalid frame scale was provided. return BAD_VALUE; } - reqSize = ui::Size(crop.width() * args.frameScale, crop.height() * args.frameScale); + reqSize = ui::Size(crop.width() * args.frameScaleX, crop.height() * args.frameScaleY); for (const auto& handle : args.excludeHandles) { sp excludeLayer = fromHandleLocked(handle).promote(); @@ -5785,13 +5787,14 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, }; return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, args.allowProtected, captureListener); + args.pixelFormat, args.allowProtected, args.grayscale, + captureListener); } status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, - const bool allowProtected, + bool allowProtected, bool grayscale, const sp& captureListener) { ATRACE_CALL(); @@ -5822,12 +5825,13 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, static_cast(reqPixelFormat), 1 /* layerCount */, usage, "screenshot"); return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - false /* regionSampling */, captureListener); + false /* regionSampling */, grayscale, captureListener); } status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, - sp& buffer, const bool regionSampling, + sp& buffer, bool regionSampling, + bool grayscale, const sp& captureListener) { ATRACE_CALL(); @@ -5843,7 +5847,7 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, if (mRefreshPending) { ALOGW("Skipping screenshot for now"); captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, regionSampling, - captureListener); + grayscale, captureListener); return; } ScreenCaptureResults captureResults; @@ -5858,7 +5862,7 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, status_t result = NO_ERROR; renderArea->render([&] { result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, forSystem, - regionSampling, captureResults); + regionSampling, grayscale, captureResults); }); captureResults.result = result; @@ -5871,7 +5875,7 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, const sp& buffer, bool forSystem, - bool regionSampling, + bool regionSampling, bool grayscale, ScreenCaptureResults& captureResults) { ATRACE_CALL(); @@ -5912,6 +5916,9 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace(); clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance; + const float colorSaturation = grayscale ? 0 : 1; + clientCompositionDisplay.colorTransform = calculateColorMatrix(colorSaturation); + const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill()); compositionengine::LayerFE::LayerSettings fillLayer; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 50d6099698..dc92f9817a 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -810,13 +810,14 @@ private: void startBootAnim(); status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, - ui::PixelFormat, const bool allowProtected, + ui::PixelFormat, bool allowProtected, bool grayscale, const sp&); status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp&, - bool regionSampling, const sp&); + bool regionSampling, bool grayscale, + const sp&); status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction, const sp&, bool forSystem, bool regionSampling, - ScreenCaptureResults&); + bool grayscale, ScreenCaptureResults&); sp getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); sp getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock); @@ -1019,6 +1020,8 @@ private: void onFrameRateFlexibilityTokenReleased(); + static mat4 calculateColorMatrix(float saturation); + void updateColorMatrixLocked(); // Verify that transaction is being called by an approved process: diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp index 93d5f2f8ec..fa1a5ed6b0 100644 --- a/services/surfaceflinger/tests/LayerState_test.cpp +++ b/services/surfaceflinger/tests/LayerState_test.cpp @@ -30,12 +30,14 @@ TEST(LayerStateTest, ParcellingDisplayCaptureArgs) { DisplayCaptureArgs args; args.pixelFormat = ui::PixelFormat::RGB_565; args.sourceCrop = Rect(0, 0, 500, 200); - args.frameScale = 2; + args.frameScaleX = 2; + args.frameScaleY = 4; args.captureSecureLayers = true; args.displayToken = new BBinder(); args.width = 10; args.height = 20; args.useIdentityTransform = true; + args.grayscale = true; Parcel p; args.write(p); @@ -46,23 +48,27 @@ TEST(LayerStateTest, ParcellingDisplayCaptureArgs) { ASSERT_EQ(args.pixelFormat, args2.pixelFormat); ASSERT_EQ(args.sourceCrop, args2.sourceCrop); - ASSERT_EQ(args.frameScale, args2.frameScale); + ASSERT_EQ(args.frameScaleX, args2.frameScaleX); + ASSERT_EQ(args.frameScaleY, args2.frameScaleY); ASSERT_EQ(args.captureSecureLayers, args2.captureSecureLayers); ASSERT_EQ(args.displayToken, args2.displayToken); ASSERT_EQ(args.width, args2.width); ASSERT_EQ(args.height, args2.height); ASSERT_EQ(args.useIdentityTransform, args2.useIdentityTransform); + ASSERT_EQ(args.grayscale, args2.grayscale); } TEST(LayerStateTest, ParcellingLayerCaptureArgs) { LayerCaptureArgs args; args.pixelFormat = ui::PixelFormat::RGB_565; args.sourceCrop = Rect(0, 0, 500, 200); - args.frameScale = 2; + args.frameScaleX = 2; + args.frameScaleY = 4; args.captureSecureLayers = true; args.layerHandle = new BBinder(); args.excludeHandles = {new BBinder(), new BBinder()}; args.childrenOnly = false; + args.grayscale = true; Parcel p; args.write(p); @@ -73,11 +79,13 @@ TEST(LayerStateTest, ParcellingLayerCaptureArgs) { ASSERT_EQ(args.pixelFormat, args2.pixelFormat); ASSERT_EQ(args.sourceCrop, args2.sourceCrop); - ASSERT_EQ(args.frameScale, args2.frameScale); + ASSERT_EQ(args.frameScaleX, args2.frameScaleX); + ASSERT_EQ(args.frameScaleY, args2.frameScaleY); ASSERT_EQ(args.captureSecureLayers, args2.captureSecureLayers); ASSERT_EQ(args.layerHandle, args2.layerHandle); ASSERT_EQ(args.excludeHandles, args2.excludeHandles); ASSERT_EQ(args.childrenOnly, args2.childrenOnly); + ASSERT_EQ(args.grayscale, args2.grayscale); } TEST(LayerStateTest, ParcellingScreenCaptureResults) { diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index 214a0cd276..51ce1d3ff9 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -487,7 +487,9 @@ TEST_F(ScreenCaptureTest, CaptureSize) { // red area to the right of the blue area mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED); - captureArgs.frameScale = 0.5f; + captureArgs.frameScaleX = 0.5f; + captureArgs.frameScaleY = 0.5f; + ScreenCapture::captureLayers(&mCapture, captureArgs); // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area. mCapture->expectColor(Rect(0, 0, 14, 14), Color::BLUE); @@ -768,6 +770,41 @@ TEST_F(ScreenCaptureTest, CaptureLayerWithUid) { mCapture->expectBorder(Rect(128, 128, 160, 160), {63, 63, 195, 255}); } +TEST_F(ScreenCaptureTest, CaptureWithGrayscale) { + sp layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32, + ISurfaceComposerClient::eFXSurfaceBufferState, + mBGSurfaceControl.get())); + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32)); + Transaction().show(layer).setLayer(layer, INT32_MAX).apply(); + + LayerCaptureArgs captureArgs; + captureArgs.layerHandle = layer->getHandle(); + + ScreenCapture::captureLayers(&mCapture, captureArgs); + mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED); + + captureArgs.grayscale = true; + + const uint8_t tolerance = 1; + + // Values based on SurfaceFlinger::calculateColorMatrix + float3 luminance{0.213f, 0.715f, 0.072f}; + + ScreenCapture::captureLayers(&mCapture, captureArgs); + + uint8_t expectedColor = luminance.r * 255; + mCapture->expectColor(Rect(0, 0, 32, 32), + Color{expectedColor, expectedColor, expectedColor, 255}, tolerance); + + ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32)); + ScreenCapture::captureLayers(&mCapture, captureArgs); + + expectedColor = luminance.b * 255; + mCapture->expectColor(Rect(0, 0, 32, 32), + Color{expectedColor, expectedColor, expectedColor, 255}, tolerance); +} + // In the following tests we verify successful skipping of a parent layer, // so we use the same verification logic and only change how we mutate // the parent layer to verify that various properties are ignored. diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 2701f472aa..eda8d79fd5 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -353,7 +353,8 @@ public: bool regionSampling) { ScreenCaptureResults captureResults; return mFlinger->renderScreenImplLocked(renderArea, traverseLayers, buffer, forSystem, - regionSampling, captureResults); + regionSampling, false /* grayscale */, + captureResults); } auto traverseLayersInLayerStack(ui::LayerStack layerStack, int32_t uid, -- cgit v1.2.3-59-g8ed1b From 7013b6f31163d9850fffec36f9dfc1ea61877a42 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 12 Feb 2021 11:16:54 -0800 Subject: Check status codes of GraphicBuffers on allocation We're getting reports of buffers transiently missing usage bits when allocated from SurfaceFlinger causing strange issues. Fatal logging when there is an allocation error will hopefully aid in triaging future bug reports. Bug: 157562905 Bug: 179786581 Test: build, boots Change-Id: I715295c0b6b3450e71181d93391dd99616f89d26 --- services/surfaceflinger/RefreshRateOverlay.cpp | 3 +++ services/surfaceflinger/RegionSamplingThread.cpp | 3 +++ services/surfaceflinger/SurfaceFlinger.cpp | 4 ++++ 3 files changed, 10 insertions(+) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 49ffc81359..b29c624d00 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -125,6 +125,9 @@ std::vector> RefreshRateOverlay::SevenSegmentDrawer::drawNumbe GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE, "RefreshRateOverlayBuffer"); + const status_t bufferStatus = buffer->initCheck(); + LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d", + bufferStatus); uint8_t* pixels; buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast(&pixels)); // Clear buffer content diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 9186538c0a..09615f920d 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -447,6 +447,9 @@ void RegionSamplingThread::captureSample() { GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); + const status_t bufferStatus = buffer->initCheck(); + LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d", + bufferStatus); } const sp captureListener = new SyncScreenCaptureListener(); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7fada820e4..cb9fae388a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5851,6 +5851,10 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(), static_cast(reqPixelFormat), 1 /* layerCount */, usage, "screenshot"); + + const status_t bufferStatus = buffer->initCheck(); + LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d", + bufferStatus); return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, false /* regionSampling */, grayscale, captureListener); } -- cgit v1.2.3-59-g8ed1b From 0d995106c0fb4480ac1de5f58667d918fa9aea62 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 24 Feb 2021 16:53:38 -0800 Subject: Dispatch texture destruction off of render thread for screenshots This is only enabled when the skia threaded variant renderengine is enabled. This essentially defers texture deletion until after drawLayers() is invoked, which shaves off time from the main SF thread. Bug: 179959621 Bug: 180767535 Test: perfetto trace Change-Id: I333091d8792fdd0dc01076c73af2956da9ee73df --- libs/renderengine/RenderEngine.cpp | 13 ++++++++----- libs/renderengine/gl/GLESRenderEngine.cpp | 3 ++- libs/renderengine/include/renderengine/RenderEngine.h | 10 ++++++++++ libs/renderengine/skia/SkiaGLRenderEngine.cpp | 6 +++--- libs/renderengine/skia/SkiaGLRenderEngine.h | 4 ---- libs/renderengine/skia/SkiaRenderEngine.h | 1 + libs/renderengine/tests/RenderEngineThreadedTest.cpp | 3 ++- libs/renderengine/threaded/RenderEngineThreaded.cpp | 8 +++++--- libs/renderengine/threaded/RenderEngineThreaded.h | 5 +++-- services/surfaceflinger/RegionSamplingThread.cpp | 6 ++++++ services/surfaceflinger/SurfaceFlinger.cpp | 15 ++++++++++++++- 11 files changed, 54 insertions(+), 20 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index b2ad22d687..79839c1f91 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -49,7 +49,8 @@ std::unique_ptr RenderEngine::create(const RenderEngineCreationArg case RenderEngineType::THREADED: ALOGD("Threaded RenderEngine with GLES Backend"); return renderengine::threaded::RenderEngineThreaded::create( - [args]() { return android::renderengine::gl::GLESRenderEngine::create(args); }); + [args]() { return android::renderengine::gl::GLESRenderEngine::create(args); }, + renderEngineType); case RenderEngineType::SKIA_GL: ALOGD("RenderEngine with SkiaGL Backend"); return renderengine::skia::SkiaGLRenderEngine::create(args); @@ -66,12 +67,14 @@ std::unique_ptr RenderEngine::create(const RenderEngineCreationArg .setPrecacheToneMapperShaderOnly(args.precacheToneMapperShaderOnly) .setSupportsBackgroundBlur(args.supportsBackgroundBlur) .setContextPriority(args.contextPriority) - .setRenderEngineType(RenderEngineType::SKIA_GL_THREADED) + .setRenderEngineType(renderEngineType) .build(); ALOGD("Threaded RenderEngine with SkiaGL Backend"); - return renderengine::threaded::RenderEngineThreaded::create([skiaArgs]() { - return android::renderengine::skia::SkiaGLRenderEngine::create(skiaArgs); - }); + return renderengine::threaded::RenderEngineThreaded::create( + [skiaArgs]() { + return android::renderengine::skia::SkiaGLRenderEngine::create(skiaArgs); + }, + renderEngineType); } case RenderEngineType::GLES: default: diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 70ae0b288a..397f0384f2 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -379,7 +379,8 @@ EGLConfig GLESRenderEngine::chooseEglConfig(EGLDisplay display, int format, bool GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface stub, EGLContext protectedContext, EGLSurface protectedStub) - : mEGLDisplay(display), + : RenderEngine(args.renderEngineType), + mEGLDisplay(display), mEGLConfig(config), mEGLContext(ctxt), mStubSurface(stub), diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 163a163fb2..572d348240 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -87,6 +87,10 @@ public: static std::unique_ptr create(const RenderEngineCreationArgs& args); + RenderEngine() : RenderEngine(RenderEngineType::GLES) {} + + RenderEngine(RenderEngineType type) : mRenderEngineType(type) {} + virtual ~RenderEngine() = 0; // ----- BEGIN DEPRECATED INTERFACE ----- @@ -192,8 +196,14 @@ public: // also supports background blur. If false, no blur will be applied when drawing layers. virtual bool supportsBackgroundBlur() = 0; + // Returns the current type of RenderEngine instance that was created. + // TODO(b/180767535): This is only implemented to allow for backend-specific behavior, which + // we should not allow in general, so remove this. + RenderEngineType getRenderEngineType() const { return mRenderEngineType; } + protected: friend class threaded::RenderEngineThreaded; + const RenderEngineType mRenderEngineType; }; struct RenderEngineCreationArgs { diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 327b04c699..7cf672a090 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -266,13 +266,13 @@ EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bo SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLContext ctxt, EGLSurface placeholder, EGLContext protectedContext, EGLSurface protectedPlaceholder) - : mEGLDisplay(display), + : SkiaRenderEngine(args.renderEngineType), + mEGLDisplay(display), mEGLContext(ctxt), mPlaceholderSurface(placeholder), mProtectedEGLContext(protectedContext), mProtectedPlaceholderSurface(protectedPlaceholder), - mUseColorManagement(args.useColorManagement), - mRenderEngineType(args.renderEngineType) { + mUseColorManagement(args.useColorManagement) { sk_sp glInterface(GrGLCreateNativeInterface()); LOG_ALWAYS_FATAL_IF(!glInterface.get()); diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 5779ae679b..a8853e0245 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -129,10 +129,6 @@ private: bool mInProtectedContext = false; // Object to capture commands send to Skia. std::unique_ptr mCapture; - - // Keep this information as a local variable to determine whether the access of the GL - // operations is working on the same threads. - const RenderEngineType mRenderEngineType = RenderEngineType::SKIA_GL; }; } // namespace skia diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 12b8586ad7..79a1040b78 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -36,6 +36,7 @@ class BlurFilter; class SkiaRenderEngine : public RenderEngine { public: static std::unique_ptr create(const RenderEngineCreationArgs& args); + SkiaRenderEngine(RenderEngineType type) : RenderEngine(type) {} ~SkiaRenderEngine() override {} virtual void primeCache() const override{}; diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index 08b672a99f..63aa4c891c 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -32,7 +32,8 @@ struct RenderEngineThreadedTest : public ::testing::Test { void SetUp() override { mThreadedRE = renderengine::threaded::RenderEngineThreaded::create( - [this]() { return std::unique_ptr(mRenderEngine); }); + [this]() { return std::unique_ptr(mRenderEngine); }, + renderengine::RenderEngine::RenderEngineType::THREADED); } std::unique_ptr mThreadedRE; diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index f4481358cf..7c7d165c04 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -34,11 +34,13 @@ namespace android { namespace renderengine { namespace threaded { -std::unique_ptr RenderEngineThreaded::create(CreateInstanceFactory factory) { - return std::make_unique(std::move(factory)); +std::unique_ptr RenderEngineThreaded::create(CreateInstanceFactory factory, + RenderEngineType type) { + return std::make_unique(std::move(factory), type); } -RenderEngineThreaded::RenderEngineThreaded(CreateInstanceFactory factory) { +RenderEngineThreaded::RenderEngineThreaded(CreateInstanceFactory factory, RenderEngineType type) + : RenderEngine(type) { ATRACE_CALL(); std::lock_guard lockThread(mThreadMutex); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 8279cbcd09..d362e176d3 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -37,9 +37,10 @@ using CreateInstanceFactory = std::function create(CreateInstanceFactory factory); + static std::unique_ptr create(CreateInstanceFactory factory, + RenderEngineType type); - RenderEngineThreaded(CreateInstanceFactory factory); + RenderEngineThreaded(CreateInstanceFactory factory, RenderEngineType type); ~RenderEngineThreaded() override; void primeCache() const override; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 09615f920d..e06bc88f7c 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -481,6 +481,12 @@ void RegionSamplingThread::captureSample() { // 1) The region sampling thread is the last owner of the buffer, and the freeing of the buffer // happens in this thread, as opposed to the main thread. // 2) The listener(s) receive their notifications prior to freeing the buffer. + if (mCachedBuffer != nullptr && mCachedBuffer != buffer) { + if (mFlinger.getRenderEngine().getRenderEngineType() == + renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) { + mFlinger.getRenderEngine().unbindExternalTextureBuffer(mCachedBuffer->getId()); + } + } mCachedBuffer = buffer; ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::noWorkNeeded)); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index da8360edaf..4215d20ceb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5858,6 +5858,15 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, regionSampling, grayscale, captureResults); }); + // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine + // Only do this when we're not doing region sampling, to allow the region sampling thread to + // manage buffer lifecycle itself. + if (!regionSampling && + getRenderEngine().getRenderEngineType() == + renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) { + getRenderEngine().unbindExternalTextureBuffer(buffer->getId()); + } + captureResults.result = result; captureListener->onScreenCaptureCompleted(captureResults); })); @@ -5977,8 +5986,12 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, base::unique_fd bufferFence; base::unique_fd drawFence; getRenderEngine().useProtectedContext(useProtected); + + // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine + const bool useFramebufferCache = getRenderEngine().getRenderEngineType() == + renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED; getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer, - /*useFramebufferCache=*/false, std::move(bufferFence), &drawFence); + useFramebufferCache, std::move(bufferFence), &drawFence); if (drawFence >= 0) { sp releaseFence = new Fence(dup(drawFence)); -- cgit v1.2.3-59-g8ed1b From dde984b2579a2e3d4430658018322b97e7b914d6 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 18 Mar 2021 12:47:36 -0700 Subject: SF: fix threads name Some of SF's threads are using a too long name which cause pthread_setname_np to fail. Fixes: 183128214 Test: systrace Change-Id: I473342857bfa0642f99c8910020114ae37559cbb --- libs/renderengine/threaded/RenderEngineThreaded.h | 2 +- services/surfaceflinger/RegionSamplingThread.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index df0551df12..7694328c84 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -73,7 +73,7 @@ private: /* ------------------------------------------------------------------------ * Threading */ - const char* const mThreadName = "RenderEngineThread"; + const char* const mThreadName = "RenderEngine"; // Protects the creation and destruction of mThread. mutable std::mutex mThreadMutex; std::thread mThread GUARDED_BY(mThreadMutex); diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index e06bc88f7c..d0032ac7fd 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -176,7 +176,7 @@ RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& s mScheduler(scheduler), mTunables(tunables), mIdleTimer( - "RegionSamplingIdleTimer", + "RegSampIdle", std::chrono::duration_cast( mTunables.mSamplingTimerTimeout), [] {}, [this] { checkForStaleLuma(); }), @@ -184,7 +184,7 @@ RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& s tunables.mSamplingDuration)), lastSampleTime(0ns) { mThread = std::thread([this]() { threadMain(); }); - pthread_setname_np(mThread.native_handle(), "RegionSamplingThread"); + pthread_setname_np(mThread.native_handle(), "RegionSampling"); mIdleTimer.start(); } -- cgit v1.2.3-59-g8ed1b From 2daef3c6ba72f364f9ac3859efc1cf2782fff67f Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 2 Apr 2021 16:29:27 -0700 Subject: Add ExternalTexture class into RenderEngine interface ExternalTexture is an RAII structure that wraps raw GraphicBuffers that are passed into RenderEngine. ExternalTexture's role is to help with managing GPU resources of GraphicBuffers by mapping buffers into textures, EGLImages, or AutoBackendTextures depending on the RenderEngine backend. Under the hood, mapExternalTextureBuffer and unmapExternalTextureBuffer (renamed from cacheExternalTextureBuffer and unbindExternalTextureBuffer respectively) are used to help tie resource management to the ExternalTexture lifetime. The main motivation for this is that currently managing buffer lifecycle has historically been errorprone and caused memory leaks, so this improves code health. As part of this: * mapExternalTextureBuffer and unmapExternalTextureBuffer are now protected methods, and are never called outside of RenderEngine with the exception of creating and destroying ExternalTextures. * Because GLESRenderEngine's output buffers are cached differently from Skia RenderEngine, if there are output-only buffers then disable the mapExternalTextureBuffer calls whenever GLESRenderEngine is used. * Custom RAII classes in the Planner and in BufferLayerConsumer are now removed since they're subsumed by ExternalTexture * RenderSurface now controls its own management of ExternalTextures in a small queue * cleanFramebufferCache is now unimplemented for Skia, because ExternalTextures are now deleted whenever a RenderSurface is deleted. Bug: 180767535 Test: libsurfaceflinger_unittest Test: libcompositionengine_test Test: librenderengine_test Test: Simulate virtual displays Test: Screen reotation Test: Movie playback on Google TV Test: Force GPU composition Test: screenshot Change-Id: I222c71e6e1c67485cdeac49e2cb829289af9efec --- libs/renderengine/Android.bp | 1 + libs/renderengine/ExternalTexture.cpp | 43 ++++ libs/renderengine/gl/GLESRenderEngine.cpp | 30 +-- libs/renderengine/gl/GLESRenderEngine.h | 11 +- .../include/renderengine/ExternalTexture.h | 61 ++++++ .../include/renderengine/LayerSettings.h | 8 +- .../include/renderengine/RenderEngine.h | 57 +++--- .../include/renderengine/mock/RenderEngine.h | 9 +- libs/renderengine/skia/AutoBackendTexture.h | 15 +- libs/renderengine/skia/Cache.cpp | 47 +++-- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 110 +++++----- libs/renderengine/skia/SkiaGLRenderEngine.h | 16 +- libs/renderengine/skia/SkiaRenderEngine.h | 10 +- libs/renderengine/tests/RenderEngineTest.cpp | 228 +++++++-------------- .../tests/RenderEngineThreadedTest.cpp | 9 +- .../renderengine/threaded/RenderEngineThreaded.cpp | 15 +- libs/renderengine/threaded/RenderEngineThreaded.h | 11 +- services/surfaceflinger/BufferLayer.cpp | 38 ++-- services/surfaceflinger/BufferLayer.h | 2 +- services/surfaceflinger/BufferLayerConsumer.cpp | 56 ++--- services/surfaceflinger/BufferLayerConsumer.h | 12 +- services/surfaceflinger/BufferStateLayer.cpp | 57 +++--- services/surfaceflinger/BufferStateLayer.h | 8 +- services/surfaceflinger/ClientCache.cpp | 13 +- services/surfaceflinger/ClientCache.h | 10 +- .../include/compositionengine/RenderSurface.h | 10 +- .../compositionengine/RenderSurfaceCreationArgs.h | 7 + .../impl/OutputLayerCompositionState.h | 4 +- .../include/compositionengine/impl/RenderSurface.h | 20 +- .../compositionengine/impl/planner/CachedSet.h | 30 +-- .../include/compositionengine/mock/RenderSurface.h | 2 +- .../CompositionEngine/src/Output.cpp | 31 +-- .../CompositionEngine/src/OutputLayer.cpp | 4 +- .../CompositionEngine/src/RenderSurface.cpp | 64 ++++-- .../CompositionEngine/src/planner/CachedSet.cpp | 14 +- .../CompositionEngine/src/planner/Planner.cpp | 7 +- .../CompositionEngine/tests/OutputLayerTest.cpp | 12 +- .../CompositionEngine/tests/OutputTest.cpp | 15 +- .../CompositionEngine/tests/RenderSurfaceTest.cpp | 46 +++-- .../tests/planner/CachedSetTest.cpp | 6 +- services/surfaceflinger/DisplayDevice.cpp | 12 +- services/surfaceflinger/Layer.cpp | 8 +- services/surfaceflinger/Layer.h | 13 +- services/surfaceflinger/RefreshRateOverlay.cpp | 15 +- services/surfaceflinger/RefreshRateOverlay.h | 11 +- services/surfaceflinger/RegionSamplingThread.cpp | 30 ++- services/surfaceflinger/RegionSamplingThread.h | 15 +- services/surfaceflinger/SurfaceFlinger.cpp | 67 +++--- services/surfaceflinger/SurfaceFlinger.h | 12 +- .../tests/unittests/CompositionTest.cpp | 33 +-- .../tests/unittests/TestableSurfaceFlinger.h | 4 +- .../tests/unittests/TransactionFrameTracerTest.cpp | 10 +- .../unittests/TransactionSurfaceFrameTest.cpp | 67 ++++-- 53 files changed, 803 insertions(+), 643 deletions(-) create mode 100644 libs/renderengine/ExternalTexture.cpp create mode 100644 libs/renderengine/include/renderengine/ExternalTexture.h (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index ec39137e24..f395ab43d8 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -48,6 +48,7 @@ filegroup { name: "librenderengine_sources", srcs: [ "Description.cpp", + "ExternalTexture.cpp", "Mesh.cpp", "RenderEngine.cpp", "Texture.cpp", diff --git a/libs/renderengine/ExternalTexture.cpp b/libs/renderengine/ExternalTexture.cpp new file mode 100644 index 0000000000..eabff58eba --- /dev/null +++ b/libs/renderengine/ExternalTexture.cpp @@ -0,0 +1,43 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "log/log_main.h" + +namespace android::renderengine { + +ExternalTexture::ExternalTexture(const sp& buffer, RenderEngine& renderEngine, + uint32_t usage) + : mBuffer(buffer), mRenderEngine(renderEngine) { + LOG_ALWAYS_FATAL_IF(buffer == nullptr, + "Attempted to bind a null buffer to an external texture!"); + // GLESRenderEngine has a separate texture cache for output buffers, + if (usage == Usage::WRITEABLE && + (mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::GLES || + mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::THREADED)) { + return; + } + mRenderEngine.mapExternalTextureBuffer(mBuffer, usage & Usage::WRITEABLE); +} + +ExternalTexture::~ExternalTexture() { + mRenderEngine.unmapExternalTextureBuffer(mBuffer); +} + +} // namespace android::renderengine diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index a2963a7c33..d87315fdc2 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -746,7 +746,8 @@ void GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, const sp& buffer) { +void GLESRenderEngine::mapExternalTextureBuffer(const sp& buffer, + bool /*isRenderable*/) { ATRACE_CALL(); mImageManager->cacheAsync(buffer, nullptr); } @@ -797,8 +798,8 @@ status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const spreleaseAsync(bufferId, nullptr); +void GLESRenderEngine::unmapExternalTextureBuffer(const sp& buffer) { + mImageManager->releaseAsync(buffer->getId(), nullptr); } std::shared_ptr GLESRenderEngine::unbindExternalTextureBufferForTesting( @@ -1102,7 +1103,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, + const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence, base::unique_fd* drawFence) { ATRACE_CALL(); @@ -1125,7 +1126,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, return BAD_VALUE; } - validateOutputBufferUsage(buffer); + validateOutputBufferUsage(buffer->getBuffer()); std::unique_ptr fbo; // Gathering layers that requested blur, we'll need them to decide when to render to an @@ -1142,11 +1143,13 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, if (blurLayersSize == 0) { fbo = std::make_unique(*this, - buffer.get()->getNativeBuffer(), + buffer->getBuffer() + .get() + ->getNativeBuffer(), useFramebufferCache); if (fbo->getStatus() != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors(); return fbo->getStatus(); } @@ -1157,7 +1160,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, mBlurFilter->setAsDrawTarget(display, blurLayers.front()->backgroundBlurRadius); if (status != NO_ERROR) { ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors(); return status; } @@ -1194,7 +1197,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, auto status = mBlurFilter->prepare(); if (status != NO_ERROR) { ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors("Can't render first blur pass"); return status; } @@ -1203,6 +1206,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, // Done blurring, time to bind the native FBO and render our blur onto it. fbo = std::make_unique(*this, buffer.get() + ->getBuffer() ->getNativeBuffer(), useFramebufferCache); status = fbo->getStatus(); @@ -1215,7 +1219,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, } if (status != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors("Can't bind native framebuffer"); return status; } @@ -1223,7 +1227,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, status = mBlurFilter->render(blurLayersSize > 1); if (status != NO_ERROR) { ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors("Can't render blur filter"); return status; } @@ -1250,7 +1254,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, disableTexture = false; isOpaque = layer->source.buffer.isOpaque; - sp gBuf = layer->source.buffer.buffer; + sp gBuf = layer->source.buffer.buffer->getBuffer(); validateInputBufferUsage(gBuf); bindExternalTextureBuffer(layer->source.buffer.textureName, gBuf, layer->source.buffer.fence); @@ -1274,7 +1278,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, // Do not cache protected EGLImage, protected memory is limited. if (gBuf->getUsage() & GRALLOC_USAGE_PROTECTED) { - unbindExternalTextureBuffer(gBuf->getId()); + unmapExternalTextureBuffer(gBuf); } } diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index cd7a86bb0e..e7ed9c01fa 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -60,16 +60,14 @@ public: void primeCache() override; void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; - void cacheExternalTextureBuffer(const sp& buffer) EXCLUDES(mRenderingMutex); - void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex); - bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; bool useProtectedContext(bool useProtectedContext) override; status_t drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; + const std::shared_ptr& buffer, + const bool useFramebufferCache, base::unique_fd&& bufferFence, + base::unique_fd* drawFence) override; bool cleanupPostRender(CleanupMode mode) override; int getContextPriority() override; bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } @@ -105,6 +103,9 @@ protected: EXCLUDES(mFramebufferImageCacheMutex); size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; + void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) + EXCLUDES(mRenderingMutex); + void unmapExternalTextureBuffer(const sp& buffer) EXCLUDES(mRenderingMutex); private: friend class BindNativeBufferAsFramebuffer; diff --git a/libs/renderengine/include/renderengine/ExternalTexture.h b/libs/renderengine/include/renderengine/ExternalTexture.h new file mode 100644 index 0000000000..07f0833d4a --- /dev/null +++ b/libs/renderengine/include/renderengine/ExternalTexture.h @@ -0,0 +1,61 @@ +/* + * Copyright 2021 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 +#include + +namespace android::renderengine { + +class RenderEngine; + +/** + * Manages GPU image resources on behalf of clients using RenderEngine. + * + * Clients of RenderEngine are required to wrap their GraphicBuffer objects as an ExternalTexture, + * which is then mapped into GPU resources required by RenderEngine. When a client no longer needs + * to use the GraphicBuffer as input into RenderEngine::drawLayers, then the client should delete + * their ExternalTexture so that resources may be freed. + */ +class ExternalTexture { +public: + // Usage specifies the rendering intent for the buffer. + enum Usage : uint32_t { + // When a buffer is not READABLE but is WRITEABLE, then GLESRenderEngine will use that as a + // hint to load the buffer into a separate cache + READABLE = 1 << 0, + + // The buffer needs to be mapped as a 2D texture if set, otherwise must be mapped as an + // external texture + WRITEABLE = 1 << 1, + }; + // Creates an ExternalTexture for the provided buffer and RenderEngine instance, with the given + // usage hint of type Usage. + ExternalTexture(const sp& buffer, RenderEngine& renderEngine, uint32_t usage); + + ~ExternalTexture(); + + // Retrieves the buffer that is bound to this texture. + const sp& getBuffer() const { return mBuffer; } + +private: + sp mBuffer; + RenderEngine& mRenderEngine; + DISALLOW_COPY_AND_ASSIGN(ExternalTexture); +}; + +} // namespace android::renderengine diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index 7661233967..c54c5ba047 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -16,11 +16,9 @@ #pragma once -#include - #include #include -#include +#include #include #include #include @@ -31,6 +29,8 @@ #include #include +#include + namespace android { namespace renderengine { @@ -39,7 +39,7 @@ struct Buffer { // Buffer containing the image that we will render. // If buffer == nullptr, then the rest of the fields in this struct will be // ignored. - sp buffer = nullptr; + std::shared_ptr buffer = nullptr; // Fence that will fire when the buffer is ready to be bound. sp fence = nullptr; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 8dd98c3ba3..c8a0f0a034 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -17,19 +17,20 @@ #ifndef SF_RENDERENGINE_H_ #define SF_RENDERENGINE_H_ -#include -#include -#include - #include #include #include +#include #include #include #include +#include +#include #include #include +#include + /** * Allows to set RenderEngine backend to GLES (default) or SkiaGL (NOT yet supported). */ @@ -51,6 +52,7 @@ class Region; namespace renderengine { +class ExternalTexture; class Image; class Mesh; class Texture; @@ -104,23 +106,6 @@ public: virtual void genTextures(size_t count, uint32_t* names) = 0; virtual void deleteTextures(size_t count, uint32_t const* names) = 0; - // Caches Image resources for this buffer, but does not bind the buffer to - // a particular texture. - // Note that work is deferred to an additional thread, i.e. this call - // is made asynchronously, but the caller can expect that cache/unbind calls - // are performed in a manner that's conflict serializable, i.e. unbinding - // a buffer should never occur before binding the buffer if the caller - // called {bind, cache}ExternalTextureBuffer before calling unbind. - virtual void cacheExternalTextureBuffer(const sp& buffer) = 0; - // Removes internal resources referenced by the bufferId. This method should be - // invoked when the caller will no longer hold a reference to a GraphicBuffer - // and needs to clean up its resources. - // Note that work is deferred to an additional thread, i.e. this call - // is made asynchronously, but the caller can expect that cache/unbind calls - // are performed in a manner that's conflict serializable, i.e. unbinding - // a buffer should never occur before binding the buffer if the caller - // called {bind, cache}ExternalTextureBuffer before calling unbind. - virtual void unbindExternalTextureBuffer(uint64_t bufferId) = 0; enum class CleanupMode { CLEAN_OUTPUT_RESOURCES, @@ -191,8 +176,9 @@ public: // now, this always returns NO_ERROR. virtual status_t drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence, base::unique_fd* drawFence) = 0; + const std::shared_ptr& buffer, + const bool useFramebufferCache, base::unique_fd&& bufferFence, + base::unique_fd* drawFence) = 0; virtual void cleanFramebufferCache() = 0; // Returns the priority this context was actually created with. Note: this may not be // the same as specified at context creation time, due to implementation limits on the @@ -213,6 +199,31 @@ public: static void validateOutputBufferUsage(const sp&); protected: + // Maps GPU resources for this buffer. + // Note that work may be deferred to an additional thread, i.e. this call + // is made asynchronously, but the caller can expect that map/unmap calls + // are performed in a manner that's conflict serializable, i.e. unmapping + // a buffer should never occur before binding the buffer if the caller + // called mapExternalTextureBuffer before calling unmap. + // Note also that if the buffer contains protected content, then mapping those GPU resources may + // be deferred until the buffer is really used for drawing. This is because typical SoCs that + // support protected memory only support a limited amount, so optimisitically mapping protected + // memory may be too burdensome. If a buffer contains protected content and the RenderEngine + // implementation supports protected context, then GPU resources may be mapped into both the + // protected and unprotected contexts. + // If the buffer may ever be written to by RenderEngine, then isRenderable must be true. + virtual void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) = 0; + // Unmaps GPU resources used by this buffer. This method should be + // invoked when the caller will no longer hold a reference to a GraphicBuffer + // and needs to clean up its resources. + // Note that if there are multiple callers holding onto the same buffer, then the buffer's + // resources may be internally ref-counted to guard against use-after-free errors. Note that + // work may be deferred to an additional thread, i.e. this call is expected to be made + // asynchronously, but the caller can expect that map/unmap calls are performed in a manner + // that's conflict serializable, i.e. unmap a buffer should never occur before binding the + // buffer if the caller called mapExternalTextureBuffer before calling unmap. + virtual void unmapExternalTextureBuffer(const sp& buffer) = 0; + friend class ExternalTexture; friend class threaded::RenderEngineThreaded; const RenderEngineType mRenderEngineType; }; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index 228553d643..27dbd1ecf3 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -39,8 +39,6 @@ public: MOCK_METHOD1(dump, void(std::string&)); MOCK_METHOD2(genTextures, void(size_t, uint32_t*)); MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*)); - MOCK_METHOD1(cacheExternalTextureBuffer, void(const sp&)); - MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t)); MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&)); MOCK_CONST_METHOD0(getMaxTextureSize, size_t()); MOCK_CONST_METHOD0(getMaxViewportDims, size_t()); @@ -50,12 +48,17 @@ public: MOCK_METHOD1(cleanupPostRender, bool(CleanupMode mode)); MOCK_METHOD6(drawLayers, status_t(const DisplaySettings&, const std::vector&, - const sp&, const bool, base::unique_fd&&, + const std::shared_ptr&, const bool, base::unique_fd&&, base::unique_fd*)); MOCK_METHOD0(cleanFramebufferCache, void()); MOCK_METHOD0(getContextPriority, int()); MOCK_METHOD0(supportsBackgroundBlur, bool()); MOCK_METHOD1(onPrimaryDisplaySizeChanged, void(ui::Size)); + +protected: + // mock renderengine still needs to implement these, but callers should never need to call them. + void mapExternalTextureBuffer(const sp&, bool) {} + void unmapExternalTextureBuffer(const sp&) {} }; } // namespace mock diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h index bb758780e1..2d61cf854b 100644 --- a/libs/renderengine/skia/AutoBackendTexture.h +++ b/libs/renderengine/skia/AutoBackendTexture.h @@ -21,9 +21,9 @@ #include #include #include +#include #include "android-base/macros.h" -#include "ui/GraphicTypes.h" namespace android { namespace renderengine { @@ -41,13 +41,18 @@ public: // of shared ownership with Skia objects, so we wrap it here instead. class LocalRef { public: - LocalRef() {} + LocalRef(AutoBackendTexture* texture) { setTexture(texture); } ~LocalRef() { // Destroying the texture is the same as setting it to null setTexture(nullptr); } + AutoBackendTexture* getTexture() const { return mTexture; } + + DISALLOW_COPY_AND_ASSIGN(LocalRef); + + private: // Sets the texture to locally ref-track. void setTexture(AutoBackendTexture* texture) { if (mTexture != nullptr) { @@ -59,12 +64,6 @@ public: mTexture->ref(); } } - - AutoBackendTexture* getTexture() const { return mTexture; } - - DISALLOW_COPY_AND_ASSIGN(LocalRef); - - private: AutoBackendTexture* mTexture = nullptr; }; diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index 1db20c0be0..1c2b2fc3ca 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -46,7 +46,7 @@ constexpr auto kDestDataSpace = ui::Dataspace::SRGB; } // namespace static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - sp dstBuffer) { + const std::shared_ptr& dstTexture) { // Somewhat arbitrary dimensions, but on screen and slightly shorter, based // on actual use. FloatRect rect(0, 0, display.physicalDisplay.width(), display.physicalDisplay.height() - 30); @@ -73,7 +73,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin auto layers = std::vector{&layer}; // The identity matrix will generate the fast shader - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, base::unique_fd(), + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); // This matrix, which has different scales for x and y, will // generate the slower (more general case) version, which has variants for translucent @@ -86,13 +86,14 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin // clang-format on for (auto translucent : {false, true}) { layer.shadow.casterIsTranslucent = translucent; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); } } static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - sp dstBuffer, sp srcBuffer) { + const std::shared_ptr& dstTexture, + const std::shared_ptr& srcTexture) { const Rect& displayRect = display.physicalDisplay; FloatRect rect(0, 0, displayRect.width(), displayRect.height()); LayerSettings layer{ @@ -103,7 +104,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting }, .source = PixelSource{.buffer = Buffer{ - .buffer = srcBuffer, + .buffer = srcTexture, .maxMasteringLuminance = 1000.f, .maxContentLuminance = 1000.f, }}, @@ -126,7 +127,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting layer.source.buffer.isOpaque = isOpaque; for (auto alpha : {half(.23999f), half(1.0f)}) { layer.alpha = alpha; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); } } @@ -135,7 +136,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting } static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - sp dstBuffer) { + const std::shared_ptr& dstTexture) { const Rect& displayRect = display.physicalDisplay; FloatRect rect(0, 0, displayRect.width(), displayRect.height()); LayerSettings layer{ @@ -143,11 +144,11 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting Geometry{ .boundaries = rect, }, - .alpha = 1, .source = PixelSource{ .solidColor = half3(0.1f, 0.2f, 0.3f), }, + .alpha = 1, }; auto layers = std::vector{&layer}; @@ -155,14 +156,14 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting layer.geometry.positionTransform = transform; for (float roundedCornersRadius : {0.0f, 0.05f, 50.f}) { layer.geometry.roundedCornersRadius = roundedCornersRadius; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); } } } static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - sp dstBuffer) { + const std::shared_ptr& dstTexture) { const Rect& displayRect = display.physicalDisplay; FloatRect rect(0, 0, displayRect.width(), displayRect.height()); LayerSettings layer{ @@ -176,7 +177,7 @@ static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings auto layers = std::vector{&layer}; for (int radius : {9, 60}) { layer.backgroundBlurRadius = radius; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); } } @@ -214,6 +215,9 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { sp dstBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usage, "primeShaderCache_dst"); + + const auto dstTexture = std::make_shared(dstBuffer, *renderengine, + ExternalTexture::Usage::WRITEABLE); // This buffer will be the source for the call to drawImageLayers. Draw // something to it as a placeholder for what an app draws. We should draw // something, but the details are not important. Make use of the shadow layer drawing step @@ -222,11 +226,16 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usage, "drawImageLayer_src"); - drawSolidLayers(renderengine, display, dstBuffer); - drawShadowLayers(renderengine, display, srcBuffer); - drawBlurLayers(renderengine, display, dstBuffer); + const auto srcTexture = + std::make_shared(srcBuffer, *renderengine, + ExternalTexture::Usage::READABLE | + ExternalTexture::Usage::WRITEABLE); + + drawSolidLayers(renderengine, display, dstTexture); + drawShadowLayers(renderengine, display, srcTexture); + drawBlurLayers(renderengine, display, dstTexture); // The majority of shaders are related to sampling images. - drawImageLayers(renderengine, display, dstBuffer, srcBuffer); + drawImageLayers(renderengine, display, dstTexture, srcTexture); // should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE; @@ -234,12 +243,12 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { sp externalBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usageExternal, "primeShaderCache_external"); + const auto externalTexture = + std::make_shared(externalBuffer, *renderengine, + ExternalTexture::Usage::READABLE); // TODO(b/184665179) doubles number of image shader compilations, but only somewhere // between 6 and 8 will occur in real uses. - drawImageLayers(renderengine, display, dstBuffer, externalBuffer); - renderengine->unbindExternalTextureBuffer(externalBuffer->getId()); - - renderengine->unbindExternalTextureBuffer(srcBuffer->getId()); + drawImageLayers(renderengine, display, dstTexture, externalTexture); const nsecs_t timeAfter = systemTime(); const float compileTimeMs = static_cast(timeAfter - timeBefore) / 1.0E6; diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 3b2c7e5f66..e781584a9b 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -329,8 +329,6 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL } SkiaGLRenderEngine::~SkiaGLRenderEngine() { - cleanFramebufferCache(); - std::lock_guard lock(mRenderingMutex); if (mBlurFilter) { delete mBlurFilter; @@ -484,7 +482,8 @@ static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destin sourceTransfer != destTransfer; } -void SkiaGLRenderEngine::cacheExternalTextureBuffer(const sp& buffer) { +void SkiaGLRenderEngine::mapExternalTextureBuffer(const sp& buffer, + bool isRenderable) { // Only run this if RE is running on its own thread. This way the access to GL // operations is guaranteed to be happening on the same thread. if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED) { @@ -505,25 +504,41 @@ void SkiaGLRenderEngine::cacheExternalTextureBuffer(const sp& buf auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache; std::lock_guard lock(mRenderingMutex); - auto iter = cache.find(buffer->getId()); - if (iter != cache.end()) { - ALOGV("Texture already exists in cache."); - } else { + mGraphicBufferExternalRefs[buffer->getId()]++; + + if (const auto& iter = cache.find(buffer->getId()); iter == cache.end()) { std::shared_ptr imageTextureRef = - std::make_shared(); - imageTextureRef->setTexture( - new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), false)); + std::make_shared( + new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), + isRenderable)); cache.insert({buffer->getId(), imageTextureRef}); } // restore the original state of the protected context if necessary useProtectedContext(protectedContextState); } -void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { +void SkiaGLRenderEngine::unmapExternalTextureBuffer(const sp& buffer) { ATRACE_CALL(); std::lock_guard lock(mRenderingMutex); - mTextureCache.erase(bufferId); - mProtectedTextureCache.erase(bufferId); + if (const auto& iter = mGraphicBufferExternalRefs.find(buffer->getId()); + iter != mGraphicBufferExternalRefs.end()) { + if (iter->second == 0) { + ALOGW("Attempted to unmap GraphicBuffer from RenderEngine texture, but the " + "ref count was already zero!", + buffer->getId()); + mGraphicBufferExternalRefs.erase(buffer->getId()); + return; + } + + iter->second--; + + if (iter->second == 0) { + mTextureCache.erase(buffer->getId()); + mProtectedTextureCache.erase(buffer->getId()); + mGraphicBufferExternalRefs.erase(buffer->getId()); + } + } } sk_sp SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp shader, @@ -621,8 +636,8 @@ private: status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, - const bool useFramebufferCache, + const std::shared_ptr& buffer, + const bool /*useFramebufferCache*/, base::unique_fd&& bufferFence, base::unique_fd* drawFence) { ATRACE_NAME("SkiaGL::drawLayers"); @@ -645,32 +660,18 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, return BAD_VALUE; } - validateOutputBufferUsage(buffer); + validateOutputBufferUsage(buffer->getBuffer()); auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext; auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache; - AHardwareBuffer_Desc bufferDesc; - AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc); - - std::shared_ptr surfaceTextureRef = nullptr; - if (useFramebufferCache) { - auto iter = cache.find(buffer->getId()); - if (iter != cache.end()) { - ALOGV("Cache hit!"); - ATRACE_NAME("Cache hit"); - surfaceTextureRef = iter->second; - } - } - if (surfaceTextureRef == nullptr || surfaceTextureRef->getTexture() == nullptr) { - ATRACE_NAME("Cache miss"); - surfaceTextureRef = std::make_shared(); - surfaceTextureRef->setTexture( - new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), true)); - if (useFramebufferCache) { - ALOGD("Adding to cache"); - cache.insert({buffer->getId(), surfaceTextureRef}); - } + std::shared_ptr surfaceTextureRef; + if (const auto& it = cache.find(buffer->getBuffer()->getId()); it != cache.end()) { + surfaceTextureRef = it->second; + } else { + surfaceTextureRef = std::make_shared( + new AutoBackendTexture(grContext.get(), buffer->getBuffer()->toAHardwareBuffer(), + true)); } const ui::Dataspace dstDataspace = @@ -876,18 +877,22 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, SkPaint paint; if (layer->source.buffer.buffer) { ATRACE_NAME("DrawImage"); - validateInputBufferUsage(layer->source.buffer.buffer); + validateInputBufferUsage(layer->source.buffer.buffer->getBuffer()); const auto& item = layer->source.buffer; std::shared_ptr imageTextureRef = nullptr; - auto iter = cache.find(item.buffer->getId()); - if (iter != cache.end()) { + + if (const auto& iter = cache.find(item.buffer->getBuffer()->getId()); + iter != cache.end()) { imageTextureRef = iter->second; } else { - imageTextureRef = std::make_shared(); - imageTextureRef->setTexture(new AutoBackendTexture(grContext.get(), - item.buffer->toAHardwareBuffer(), - false)); - cache.insert({item.buffer->getId(), imageTextureRef}); + // If we didn't find the image in the cache, then create a local ref but don't cache + // it. If we're using skia, we're guaranteed to run on a dedicated GPU thread so if + // we didn't find anything in the cache then we intentionally did not cache this + // buffer's resources. + imageTextureRef = std::make_shared( + new AutoBackendTexture(grContext.get(), + item.buffer->getBuffer()->toAHardwareBuffer(), + false)); } sk_sp image = @@ -1200,15 +1205,6 @@ EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay dis return eglCreatePbufferSurface(display, placeholderConfig, attributes.data()); } -void SkiaGLRenderEngine::cleanFramebufferCache() { - // TODO(b/180767535) Remove this method and use b/180767535 instead, which would allow - // SF to control texture lifecycle more tightly rather than through custom hooks into RE. - std::lock_guard lock(mRenderingMutex); - mRuntimeEffects.clear(); - mProtectedTextureCache.clear(); - mTextureCache.clear(); -} - int SkiaGLRenderEngine::getContextPriority() { int value; eglQueryContext(mEGLDisplay, mEGLContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &value); @@ -1281,6 +1277,12 @@ void SkiaGLRenderEngine::dump(std::string& result) { StringAppendF(&result, "Skia's Wrapped Objects:\n"); gpuReporter.logOutput(result, true); + StringAppendF(&result, "RenderEngine tracked buffers: %zu\n", + mGraphicBufferExternalRefs.size()); + StringAppendF(&result, "Dumping buffer ids...\n"); + for (const auto& [id, refCounts] : mGraphicBufferExternalRefs) { + StringAppendF(&result, "- 0x%" PRIx64 " - %d refs \n", id, refCounts); + } StringAppendF(&result, "RenderEngine AHB/BackendTexture cache size: %zu\n", mTextureCache.size()); StringAppendF(&result, "Dumping buffer ids...\n"); diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 8e77c16b40..e71c560a1f 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -52,13 +53,12 @@ public: ~SkiaGLRenderEngine() override EXCLUDES(mRenderingMutex); void primeCache() override; - void cacheExternalTextureBuffer(const sp& buffer) override; - void unbindExternalTextureBuffer(uint64_t bufferId) override; status_t drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; - void cleanFramebufferCache() override; + const std::shared_ptr& buffer, + const bool useFramebufferCache, base::unique_fd&& bufferFence, + base::unique_fd* drawFence) override; + void cleanFramebufferCache() override {} int getContextPriority() override; bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; @@ -72,6 +72,8 @@ protected: void dump(std::string& result) override; size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; + void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) override; + void unmapExternalTextureBuffer(const sp& buffer) override; private: static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); @@ -114,7 +116,9 @@ private: const PixelFormat mDefaultPixelFormat; const bool mUseColorManagement; - // Cache of GL textures that we'll store per GraphicBuffer ID + // Number of external holders of ExternalTexture references, per GraphicBuffer ID. + std::unordered_map mGraphicBufferExternalRefs GUARDED_BY(mRenderingMutex); + // Cache of GL textures that we'll store per GraphicBuffer ID, sliced by GPU context. std::unordered_map> mTextureCache GUARDED_BY(mRenderingMutex); std::unordered_map> diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 51ef088a25..308c5ffa9f 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -42,15 +42,12 @@ public: virtual void primeCache() override{}; virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override{}; virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{}; - virtual void cacheExternalTextureBuffer(const sp& /*buffer*/){}; - virtual void unbindExternalTextureBuffer(uint64_t /*bufferId*/){}; - virtual bool isProtected() const override { return false; } // mInProtectedContext; } virtual bool supportsProtectedContent() const override { return false; }; virtual bool useProtectedContext(bool /*useProtectedContext*/) override { return false; }; virtual status_t drawLayers(const DisplaySettings& /*display*/, const std::vector& /*layers*/, - const sp& /*buffer*/, + const std::shared_ptr& /*buffer*/, const bool /*useFramebufferCache*/, base::unique_fd&& /*bufferFence*/, base::unique_fd* /*drawFence*/) override { @@ -60,6 +57,11 @@ public: virtual int getContextPriority() override { return 0; } virtual void assertShadersCompiled(int numShaders) {} virtual int reportShadersCompiled() { return 0; } + +protected: + virtual void mapExternalTextureBuffer(const sp& /*buffer*/, + bool /*isRenderable*/) override; + virtual void unmapExternalTextureBuffer(const sp& /*buffer*/) override; }; } // namespace skia diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 7846156383..d63c88bc02 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -160,27 +161,42 @@ public: class RenderEngineTest : public ::testing::TestWithParam> { public: - static sp allocateDefaultBuffer() { - return new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, - "output"); + std::shared_ptr allocateDefaultBuffer() { + return std::make_shared< + renderengine:: + ExternalTexture>(new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, + DEFAULT_DISPLAY_HEIGHT, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE, + "output"), + *mRE, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); } // Allocates a 1x1 buffer to fill with a solid color - static sp allocateSourceBuffer(uint32_t width, uint32_t height) { - return new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_TEXTURE, - "input"); + std::shared_ptr allocateSourceBuffer(uint32_t width, + uint32_t height) { + return std::make_shared< + renderengine:: + ExternalTexture>(new GraphicBuffer(width, height, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_TEXTURE, + "input"), + *mRE, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); } RenderEngineTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - mBuffer = allocateDefaultBuffer(); } ~RenderEngineTest() { @@ -211,20 +227,21 @@ public: } uint8_t* pixels; - mBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + mBuffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); file << "P6\n"; - file << mBuffer->getWidth() << "\n"; - file << mBuffer->getHeight() << "\n"; + file << mBuffer->getBuffer()->getWidth() << "\n"; + file << mBuffer->getBuffer()->getHeight() << "\n"; file << 255 << "\n"; - std::vector outBuffer(mBuffer->getWidth() * mBuffer->getHeight() * 3); + std::vector outBuffer(mBuffer->getBuffer()->getWidth() * + mBuffer->getBuffer()->getHeight() * 3); auto outPtr = reinterpret_cast(outBuffer.data()); - for (int32_t j = 0; j < mBuffer->getHeight(); j++) { - const uint8_t* src = pixels + (mBuffer->getStride() * j) * 4; - for (int32_t i = 0; i < mBuffer->getWidth(); i++) { + for (int32_t j = 0; j < mBuffer->getBuffer()->getHeight(); j++) { + const uint8_t* src = pixels + (mBuffer->getBuffer()->getStride() * j) * 4; + for (int32_t i = 0; i < mBuffer->getBuffer()->getWidth(); i++) { // Only copy R, G and B components outPtr[0] = src[0]; outPtr[1] = src[1]; @@ -235,7 +252,7 @@ public: } } file.write(reinterpret_cast(outBuffer.data()), outBuffer.size()); - mBuffer->unlock(); + mBuffer->getBuffer()->unlock(); } void expectBufferColor(const Region& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { @@ -262,13 +279,13 @@ public: void expectBufferColor(const Rect& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a, std::function colorCompare) { uint8_t* pixels; - mBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + mBuffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); int32_t maxFails = 10; int32_t fails = 0; for (int32_t j = 0; j < region.getHeight(); j++) { - const uint8_t* src = - pixels + (mBuffer->getStride() * (region.top + j) + region.left) * 4; + const uint8_t* src = pixels + + (mBuffer->getBuffer()->getStride() * (region.top + j) + region.left) * 4; for (int32_t i = 0; i < region.getWidth(); i++) { const uint8_t expected[4] = {r, g, b, a}; bool equal = colorCompare(src, expected); @@ -289,7 +306,7 @@ public: break; } } - mBuffer->unlock(); + mBuffer->getBuffer()->unlock(); } void expectAlpha(const Rect& rect, uint8_t a) { @@ -387,7 +404,6 @@ public: base::unique_fd fence; status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fence); - mCurrentBuffer = mBuffer; int fd = fence.release(); if (fd >= 0) { @@ -397,7 +413,7 @@ public: ASSERT_EQ(NO_ERROR, status); if (layers.size() > 0 && mGLESRE != nullptr) { - ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId())); + ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId())); } } @@ -503,17 +519,11 @@ public: void initializeRenderEngine(); std::unique_ptr mRE; + std::shared_ptr mBuffer; // GLESRenderEngine for testing GLES-specific behavior. // Owened by mRE, but this is downcasted. renderengine::gl::GLESRenderEngine* mGLESRE = nullptr; - // Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to - // be freed *after* RenderEngine is destroyed, so that the EGL image is - // destroyed first. - sp mCurrentBuffer; - - sp mBuffer; - std::vector mTexNames; }; @@ -530,6 +540,7 @@ void RenderEngineTest::initializeRenderEngine() { } else { mRE = renderEngineFactory->createRenderEngine(); } + mBuffer = allocateDefaultBuffer(); } struct ColorSourceVariant { @@ -566,18 +577,18 @@ template struct BufferSourceVariant { static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b, RenderEngineTest* fixture) { - sp buf = RenderEngineTest::allocateSourceBuffer(1, 1); + const auto buf = fixture->allocateSourceBuffer(1, 1); uint32_t texName; fixture->mRE->genTextures(1, &texName); fixture->mTexNames.push_back(texName); uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); - for (int32_t j = 0; j < buf->getHeight(); j++) { - uint8_t* iter = pixels + (buf->getStride() * j) * 4; - for (int32_t i = 0; i < buf->getWidth(); i++) { + for (int32_t j = 0; j < buf->getBuffer()->getHeight(); j++) { + uint8_t* iter = pixels + (buf->getBuffer()->getStride() * j) * 4; + for (int32_t i = 0; i < buf->getBuffer()->getWidth(); i++) { iter[0] = uint8_t(r * 255); iter[1] = uint8_t(g * 255); iter[2] = uint8_t(b * 255); @@ -586,7 +597,7 @@ struct BufferSourceVariant { } } - buf->unlock(); + buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1012,14 +1023,14 @@ void RenderEngineTest::fillRedBufferTextureTransform() { layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; // Here will allocate a checker board texture, but transform texture // coordinates so that only the upper left is applied. - sp buf = allocateSourceBuffer(2, 2); + const auto buf = allocateSourceBuffer(2, 2); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); // Red top left, Green top right, Blue bottom left, Black bottom right pixels[0] = 255; pixels[1] = 0; @@ -1033,7 +1044,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() { pixels[9] = 0; pixels[10] = 255; pixels[11] = 255; - buf->unlock(); + buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1061,19 +1072,19 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() { std::vector layers; renderengine::LayerSettings layer; - sp buf = allocateSourceBuffer(1, 1); + const auto buf = allocateSourceBuffer(1, 1); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); pixels[0] = 255; pixels[1] = 0; pixels[2] = 0; pixels[3] = 255; - buf->unlock(); + buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1100,19 +1111,19 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() { std::vector layers; renderengine::LayerSettings layer; - sp buf = allocateSourceBuffer(1, 1); + const auto buf = allocateSourceBuffer(1, 1); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); pixels[0] = 255; pixels[1] = 0; pixels[2] = 0; pixels[3] = 255; - buf->unlock(); + buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1233,8 +1244,7 @@ TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) { } TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) { - const auto& renderEngineFactory = GetParam(); - mRE = renderEngineFactory->createRenderEngine(); + initializeRenderEngine(); renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1295,7 +1305,6 @@ TEST_P(RenderEngineTest, drawLayers_nullOutputFence) { layers.push_back(&layer); status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), nullptr); - mCurrentBuffer = mBuffer; ASSERT_EQ(NO_ERROR, status); expectBufferColor(fullscreenRect(), 255, 0, 0, 255); } @@ -1323,9 +1332,8 @@ TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) { layers.push_back(&layer); status_t status = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd(), nullptr); - mCurrentBuffer = mBuffer; ASSERT_EQ(NO_ERROR, status); - ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId())); + ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId())); expectBufferColor(fullscreenRect(), 255, 0, 0, 255); } @@ -1574,98 +1582,6 @@ TEST_P(RenderEngineTest, drawLayers_clearRegion) { clearRegion(); } -TEST_P(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) { - const auto& renderEngineFactory = GetParam(); - - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - // GLES-specific test - return; - } - - initializeRenderEngine(); - - renderengine::DisplaySettings settings; - settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - settings.physicalDisplay = fullscreenRect(); - settings.clip = fullscreenRect(); - - std::vector layers; - - renderengine::LayerSettings layer; - layer.geometry.boundaries = fullscreenRect().toFloatRect(); - BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); - - layers.push_back(&layer); - invokeDraw(settings, layers); - uint64_t bufferId = layer.source.buffer.buffer->getId(); - EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId)); - std::shared_ptr barrier = - mGLESRE->unbindExternalTextureBufferForTesting(bufferId); - std::lock_guard lock(barrier->mutex); - ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), - [&]() REQUIRES(barrier->mutex) { - return barrier->isOpen; - })); - EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId)); - EXPECT_EQ(NO_ERROR, barrier->result); -} - -TEST_P(RenderEngineTest, cacheExternalBuffer_withNullBuffer) { - const auto& renderEngineFactory = GetParam(); - - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - // GLES-specific test - return; - } - - initializeRenderEngine(); - - std::shared_ptr barrier = - mGLESRE->cacheExternalTextureBufferForTesting(nullptr); - std::lock_guard lock(barrier->mutex); - ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), - [&]() REQUIRES(barrier->mutex) { - return barrier->isOpen; - })); - EXPECT_TRUE(barrier->isOpen); - EXPECT_EQ(BAD_VALUE, barrier->result); -} - -TEST_P(RenderEngineTest, cacheExternalBuffer_cachesImages) { - const auto& renderEngineFactory = GetParam(); - - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - // GLES-specific test - return; - } - - initializeRenderEngine(); - - sp buf = allocateSourceBuffer(1, 1); - uint64_t bufferId = buf->getId(); - std::shared_ptr barrier = - mGLESRE->cacheExternalTextureBufferForTesting(buf); - { - std::lock_guard lock(barrier->mutex); - ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), - [&]() REQUIRES(barrier->mutex) { - return barrier->isOpen; - })); - EXPECT_EQ(NO_ERROR, barrier->result); - } - EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId)); - barrier = mGLESRE->unbindExternalTextureBufferForTesting(bufferId); - { - std::lock_guard lock(barrier->mutex); - ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), - [&]() REQUIRES(barrier->mutex) { - return barrier->isOpen; - })); - EXPECT_EQ(NO_ERROR, barrier->result); - } - EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId)); -} - TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) { initializeRenderEngine(); @@ -1858,7 +1774,7 @@ TEST_P(RenderEngineTest, cleanupPostRender_whenCleaningAll_replacesTextureMemory sync_wait(fd, -1); } - uint64_t bufferId = layer.source.buffer.buffer->getId(); + uint64_t bufferId = layer.source.buffer.buffer->getBuffer()->getId(); uint32_t texName = layer.source.buffer.textureName; EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId)); EXPECT_EQ(bufferId, mGLESRE->getBufferIdForTextureNameForTesting(texName)); @@ -1966,16 +1882,16 @@ TEST_P(RenderEngineTest, testDisableBlendingBuffer) { // The next layer will overwrite redLayer with a GraphicBuffer that is green // applied with a translucent alpha. - auto buf = allocateSourceBuffer(1, 1); + const auto buf = allocateSourceBuffer(1, 1); { uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); pixels[0] = 0; pixels[1] = 255; pixels[2] = 0; pixels[3] = 255; - buf->unlock(); + buf->getBuffer()->unlock(); } const renderengine::LayerSettings greenLayer{ diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index b093e88d4f..e3917cce09 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -162,15 +162,18 @@ TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsTrue) { TEST_F(RenderEngineThreadedTest, drawLayers) { renderengine::DisplaySettings settings; std::vector layers; - sp buffer = new GraphicBuffer(); + std::shared_ptr buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), *mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); base::unique_fd bufferFence; base::unique_fd drawFence; EXPECT_CALL(*mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings&, const std::vector&, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { return NO_ERROR; }); + const std::shared_ptr&, const bool, + base::unique_fd&&, base::unique_fd*) -> status_t { return NO_ERROR; }); status_t result = mThreadedRE->drawLayers(settings, layers, buffer, false, std::move(bufferFence), &drawFence); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index 194c7da1c7..c9f6296b49 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -157,27 +157,28 @@ void RenderEngineThreaded::deleteTextures(size_t count, uint32_t const* names) { resultFuture.wait(); } -void RenderEngineThreaded::cacheExternalTextureBuffer(const sp& buffer) { +void RenderEngineThreaded::mapExternalTextureBuffer(const sp& buffer, + bool isRenderable) { // This function is designed so it can run asynchronously, so we do not need to wait // for the futures. { std::lock_guard lock(mThreadMutex); mFunctionCalls.push([=](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::cacheExternalTextureBuffer"); - instance.cacheExternalTextureBuffer(buffer); + ATRACE_NAME("REThreaded::mapExternalTextureBuffer"); + instance.mapExternalTextureBuffer(buffer, isRenderable); }); } mCondition.notify_one(); } -void RenderEngineThreaded::unbindExternalTextureBuffer(uint64_t bufferId) { +void RenderEngineThreaded::unmapExternalTextureBuffer(const sp& buffer) { // This function is designed so it can run asynchronously, so we do not need to wait // for the futures. { std::lock_guard lock(mThreadMutex); mFunctionCalls.push([=](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::unbindExternalTextureBuffer"); - instance.unbindExternalTextureBuffer(bufferId); + ATRACE_NAME("REThreaded::unmapExternalTextureBuffer"); + instance.unmapExternalTextureBuffer(buffer); }); } mCondition.notify_one(); @@ -239,7 +240,7 @@ bool RenderEngineThreaded::cleanupPostRender(CleanupMode mode) { status_t RenderEngineThreaded::drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, + const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence, base::unique_fd* drawFence) { diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 61ae9b8cf8..eb6098ed8d 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -48,8 +48,6 @@ public: void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; - void cacheExternalTextureBuffer(const sp& buffer) override; - void unbindExternalTextureBuffer(uint64_t bufferId) override; size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; @@ -60,14 +58,19 @@ public: status_t drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; + const std::shared_ptr& buffer, + const bool useFramebufferCache, base::unique_fd&& bufferFence, + base::unique_fd* drawFence) override; void cleanFramebufferCache() override; int getContextPriority() override; bool supportsBackgroundBlur() override; void onPrimaryDisplaySizeChanged(ui::Size size) override; +protected: + void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) override; + void unmapExternalTextureBuffer(const sp& buffer) override; + private: void threadMain(CreateInstanceFactory factory); void waitUntilInitialized() const; diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index be9bce0795..13ac7c3563 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -188,7 +188,7 @@ std::optional BufferLayer::prepareCli const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || (isSecure() && !targetSettings.isSecure); const bool bufferCanBeUsedAsHwTexture = - mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; + mBufferInfo.mBuffer->getBuffer()->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; compositionengine::LayerFE::LayerSettings& layer = *result; if (blackOutLayer || !bufferCanBeUsedAsHwTexture) { ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable", @@ -213,7 +213,7 @@ std::optional BufferLayer::prepareCli ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel : defaultMaxContentLuminance; layer.frameNumber = mCurrentFrameNumber; - layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0; + layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer()->getId() : 0; const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering(); @@ -314,7 +314,7 @@ void BufferLayer::preparePerFrameCompositionState() { : Hwc2::IComposerClient::Composition::DEVICE; } - compositionState->buffer = mBufferInfo.mBuffer; + compositionState->buffer = mBufferInfo.mBuffer->getBuffer(); compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mBufferInfo.mBufferSlot; @@ -442,7 +442,7 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, void BufferLayer::gatherBufferInfo() { mBufferInfo.mPixelFormat = - !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->format; + !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getBuffer()->format; mBufferInfo.mFrameLatencyNeeded = true; } @@ -544,10 +544,10 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, } if (oldBufferInfo.mBuffer != nullptr) { - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); - if (bufWidth != uint32_t(oldBufferInfo.mBuffer->width) || - bufHeight != uint32_t(oldBufferInfo.mBuffer->height)) { + uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); + if (bufWidth != uint32_t(oldBufferInfo.mBuffer->getBuffer()->width) || + bufHeight != uint32_t(oldBufferInfo.mBuffer->getBuffer()->height)) { recomputeVisibleRegions = true; } } @@ -612,8 +612,8 @@ uint32_t BufferLayer::getEffectiveScalingMode() const { } bool BufferLayer::isProtected() const { - const sp& buffer(mBufferInfo.mBuffer); - return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED); + return (mBufferInfo.mBuffer != nullptr) && + (mBufferInfo.mBuffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED); } // h/w composer set-up @@ -727,8 +727,8 @@ Rect BufferLayer::getBufferSize(const State& s) const { return Rect::INVALID_RECT; } - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); + uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { @@ -759,8 +759,8 @@ FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const return parentBounds; } - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); + uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { @@ -802,7 +802,7 @@ Rect BufferLayer::getBufferCrop() const { return mBufferInfo.mCrop; } else if (mBufferInfo.mBuffer != nullptr) { // otherwise we use the whole buffer - return mBufferInfo.mBuffer->getBounds(); + return mBufferInfo.mBuffer->getBuffer()->getBounds(); } else { // if we don't have a buffer yet, we use an empty/invalid crop return Rect(); @@ -847,12 +847,14 @@ ui::Dataspace BufferLayer::translateDataspace(ui::Dataspace dataspace) { } sp BufferLayer::getBuffer() const { - return mBufferInfo.mBuffer; + return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr; } void BufferLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) { - GLConsumer::computeTransformMatrix(outMatrix, mBufferInfo.mBuffer, mBufferInfo.mCrop, - mBufferInfo.mTransform, filteringEnabled); + GLConsumer::computeTransformMatrix(outMatrix, + mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() + : nullptr, + mBufferInfo.mCrop, mBufferInfo.mTransform, filteringEnabled); } void BufferLayer::setInitialValuesForClone(const sp& clonedFrom) { diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index b8d3f12322..855324710e 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -134,7 +134,7 @@ protected: PixelFormat mPixelFormat{PIXEL_FORMAT_NONE}; bool mTransformToDisplayInverse{false}; - sp mBuffer; + std::shared_ptr mBuffer; int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT}; bool mFrameLatencyNeeded{false}; diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 69d2d11a4d..96b22478ab 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -167,7 +166,7 @@ void BufferLayerConsumer::setReleaseFence(const sp& fence) { } auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer - : mCurrentTextureBuffer->graphicBuffer(); + : mCurrentTextureBuffer->getBuffer(); auto err = addReleaseFence(slot, buffer, fence); if (err != OK) { BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); @@ -206,9 +205,11 @@ status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t pres // before, so we need to clean up old references. if (item->mGraphicBuffer != nullptr) { std::lock_guard lock(mImagesMutex); - if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->graphicBuffer() == nullptr || - mImages[item->mSlot]->graphicBuffer()->getId() != item->mGraphicBuffer->getId()) { - mImages[item->mSlot] = std::make_shared(item->mGraphicBuffer, mRE); + if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->getBuffer() == nullptr || + mImages[item->mSlot]->getBuffer()->getId() != item->mGraphicBuffer->getId()) { + mImages[item->mSlot] = std::make_shared< + renderengine::ExternalTexture>(item->mGraphicBuffer, mRE, + renderengine::ExternalTexture::Usage::READABLE); } } @@ -222,8 +223,8 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, int slot = item.mSlot; BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, - (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->graphicBuffer() != nullptr) - ? mCurrentTextureBuffer->graphicBuffer()->handle + (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->getBuffer() != nullptr) + ? mCurrentTextureBuffer->getBuffer()->handle : 0, slot, mSlots[slot].mGraphicBuffer->handle); @@ -231,7 +232,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, // releaseBufferLocked() if we're in shared buffer mode and both buffers are // the same. - std::shared_ptr nextTextureBuffer; + std::shared_ptr nextTextureBuffer; { std::lock_guard lock(mImagesMutex); nextTextureBuffer = mImages[slot]; @@ -241,7 +242,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (pendingRelease == nullptr) { status_t status = - releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->graphicBuffer()); + releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->getBuffer()); if (status < NO_ERROR) { BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), status); @@ -250,7 +251,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, } } else { pendingRelease->currentTexture = mCurrentTexture; - pendingRelease->graphicBuffer = mCurrentTextureBuffer->graphicBuffer(); + pendingRelease->graphicBuffer = mCurrentTextureBuffer->getBuffer(); pendingRelease->isPending = true; } } @@ -301,14 +302,14 @@ void BufferLayerConsumer::setFilteringEnabled(bool enabled) { void BufferLayerConsumer::computeCurrentTransformMatrixLocked() { BLC_LOGV("computeCurrentTransformMatrixLocked"); - if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->graphicBuffer() == nullptr) { + if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->getBuffer() == nullptr) { BLC_LOGD("computeCurrentTransformMatrixLocked: " "mCurrentTextureBuffer is nullptr"); } GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, mCurrentTextureBuffer == nullptr ? nullptr - : mCurrentTextureBuffer->graphicBuffer(), + : mCurrentTextureBuffer->getBuffer(), getCurrentCropLocked(), mCurrentTransform, mFilteringEnabled); } @@ -360,7 +361,8 @@ int BufferLayerConsumer::getCurrentApi() const { return mCurrentApi; } -sp BufferLayerConsumer::getCurrentBuffer(int* outSlot, sp* outFence) const { +std::shared_ptr BufferLayerConsumer::getCurrentBuffer( + int* outSlot, sp* outFence) const { Mutex::Autolock lock(mMutex); if (outSlot != nullptr) { @@ -371,7 +373,7 @@ sp BufferLayerConsumer::getCurrentBuffer(int* outSlot, sp* *outFence = mCurrentFence; } - return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer->graphicBuffer(); + return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer; } Rect BufferLayerConsumer::getCurrentCrop() const { @@ -456,10 +458,12 @@ void BufferLayerConsumer::onSidebandStreamChanged() { void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) { if (item.mGraphicBuffer != nullptr && item.mSlot != BufferQueue::INVALID_BUFFER_SLOT) { std::lock_guard lock(mImagesMutex); - const std::shared_ptr& oldImage = mImages[item.mSlot]; - if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr || - oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) { - mImages[item.mSlot] = std::make_shared(item.mGraphicBuffer, mRE); + const std::shared_ptr& oldImage = mImages[item.mSlot]; + if (oldImage == nullptr || oldImage->getBuffer() == nullptr || + oldImage->getBuffer()->getId() != item.mGraphicBuffer->getId()) { + mImages[item.mSlot] = std::make_shared< + renderengine::ExternalTexture>(item.mGraphicBuffer, mRE, + renderengine::ExternalTexture::Usage::READABLE); } } } @@ -499,22 +503,6 @@ void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const ConsumerBase::dumpLocked(result, prefix); } - -BufferLayerConsumer::Image::Image(const sp& graphicBuffer, - renderengine::RenderEngine& engine) - : mGraphicBuffer(graphicBuffer), mRE(engine) { - if (graphicBuffer != nullptr && (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED)) { - return; - } - mRE.cacheExternalTextureBuffer(mGraphicBuffer); -} - -BufferLayerConsumer::Image::~Image() { - if (mGraphicBuffer != nullptr) { - ALOGV("Destroying buffer: %" PRId64, mGraphicBuffer->getId()); - mRE.unbindExternalTextureBuffer(mGraphicBuffer->getId()); - } -} }; // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index dd39214aff..9ed80b46bd 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -21,12 +21,11 @@ #include #include #include - +#include #include #include #include #include - #include #include #include @@ -39,7 +38,6 @@ class String8; namespace renderengine { class RenderEngine; -class Image; } // namespace renderengine /* @@ -153,7 +151,8 @@ public: // When outSlot is not nullptr, the current buffer slot index is also // returned. Simiarly, when outFence is not nullptr, the current output // fence is returned. - sp getCurrentBuffer(int* outSlot = nullptr, sp* outFence = nullptr) const; + std::shared_ptr getCurrentBuffer( + int* outSlot = nullptr, sp* outFence = nullptr) const; // getCurrentCrop returns the cropping rectangle of the current buffer. Rect getCurrentCrop() const; @@ -258,7 +257,7 @@ private: // mCurrentTextureBuffer is the buffer containing the current texture. It's // possible that this buffer is not associated with any buffer slot, so we // must track it separately in order to support the getCurrentBuffer method. - std::shared_ptr mCurrentTextureBuffer; + std::shared_ptr mCurrentTextureBuffer; // mCurrentCrop is the crop rectangle that applies to the current texture. // It gets set each time updateTexImage is called. @@ -337,7 +336,8 @@ private: int mCurrentTexture; // Shadow buffer cache for cleaning up renderengine references. - std::shared_ptr mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex); + std::shared_ptr + mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex); // Separate mutex guarding the shadow buffer cache. // mImagesMutex can be manipulated with binder threads (e.g. onBuffersAllocated) diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index ed826a0100..c533969a5c 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -71,14 +71,8 @@ BufferStateLayer::~BufferStateLayer() { // original layer and the clone should be removed at the same time so there shouldn't be any // issue with the clone layer trying to use the texture. if (mBufferInfo.mBuffer != nullptr && !isClone()) { - // Ensure that mBuffer is uncached from RenderEngine here, as - // RenderEngine may have been using the buffer as an external texture - // after the client uncached the buffer. - auto& engine(mFlinger->getRenderEngine()); - const uint64_t bufferId = mBufferInfo.mBuffer->getId(); - engine.unbindExternalTextureBuffer(bufferId); - callReleaseBufferCallback(mDrawingState.releaseBufferListener, mBufferInfo.mBuffer, - mBufferInfo.mFence); + callReleaseBufferCallback(mDrawingState.releaseBufferListener, + mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFence); } } @@ -363,8 +357,9 @@ bool BufferStateLayer::addFrameEvent(const sp& acquireFence, nsecs_t post return true; } -bool BufferStateLayer::setBuffer(const sp& buffer, const sp& acquireFence, - nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, +bool BufferStateLayer::setBuffer(const std::shared_ptr& buffer, + const sp& acquireFence, nsecs_t postTime, + nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, std::optional dequeueTime, const FrameTimelineInfo& info, const sp& releaseBufferListener) { @@ -372,12 +367,14 @@ bool BufferStateLayer::setBuffer(const sp& buffer, const spgetBuffer() != mDrawingState.buffer->getBuffer()) { // If mCurrentState has a buffer, and we are about to update again // before swapping to drawing state, then the first buffer will be // dropped and we should decrement the pending buffer count and // call any release buffer callbacks if set. - callReleaseBufferCallback(mCurrentState.releaseBufferListener, mCurrentState.buffer, + callReleaseBufferCallback(mCurrentState.releaseBufferListener, + mCurrentState.buffer->getBuffer(), mCurrentState.acquireFence); decrementPendingBufferCount(); if (mCurrentState.bufferSurfaceFrameTX != nullptr) { @@ -415,8 +412,8 @@ bool BufferStateLayer::setBuffer(const sp& buffer, const spgetId(); + if (buffer && dequeueTime && *dequeueTime != 0) { + const uint64_t bufferId = buffer->getBuffer()->getId(); mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str()); mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime, FrameTracer::FrameEvent::DEQUEUE); @@ -424,8 +421,8 @@ bool BufferStateLayer::setBuffer(const sp& buffer, const spwidth; - mCurrentState.height = mCurrentState.buffer->height; + mCurrentState.width = mCurrentState.buffer->getBuffer()->getWidth(); + mCurrentState.height = mCurrentState.buffer->getBuffer()->getHeight(); return true; } @@ -674,7 +671,7 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse } const int32_t layerId = getSequence(); - const uint64_t bufferId = mDrawingState.buffer->getId(); + const uint64_t bufferId = mDrawingState.buffer->getBuffer()->getId(); const uint64_t frameNumber = mDrawingState.frameNumber; const auto acquireFence = std::make_shared(mDrawingState.acquireFence); mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence); @@ -708,7 +705,7 @@ status_t BufferStateLayer::updateActiveBuffer() { return BAD_VALUE; } - if (s.buffer != mBufferInfo.mBuffer) { + if (!mBufferInfo.mBuffer || s.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) { decrementPendingBufferCount(); } @@ -827,13 +824,13 @@ uint32_t BufferStateLayer::getEffectiveScalingMode() const { Rect BufferStateLayer::computeCrop(const State& s) { if (s.crop.isEmpty() && s.buffer) { - return s.buffer->getBounds(); + return s.buffer->getBuffer()->getBounds(); } else if (s.buffer) { Rect crop = s.crop; crop.left = std::max(crop.left, 0); crop.top = std::max(crop.top, 0); - uint32_t bufferWidth = s.buffer->getWidth(); - uint32_t bufferHeight = s.buffer->getHeight(); + uint32_t bufferWidth = s.buffer->getBuffer()->getWidth(); + uint32_t bufferHeight = s.buffer->getBuffer()->getHeight(); if (bufferHeight <= std::numeric_limits::max() && bufferWidth <= std::numeric_limits::max()) { crop.right = std::min(crop.right, static_cast(bufferWidth)); @@ -841,7 +838,7 @@ Rect BufferStateLayer::computeCrop(const State& s) { } if (!crop.isValid()) { // Crop rect is out of bounds, return whole buffer - return s.buffer->getBounds(); + return s.buffer->getBuffer()->getBounds(); } return crop; } @@ -863,8 +860,8 @@ bool BufferStateLayer::bufferNeedsFiltering() const { return false; } - uint32_t bufferWidth = s.buffer->width; - uint32_t bufferHeight = s.buffer->height; + uint32_t bufferWidth = s.buffer->getBuffer()->width; + uint32_t bufferHeight = s.buffer->getBuffer()->height; // Undo any transformations on the buffer and return the result. if (s.bufferTransform & ui::Transform::ROT_90) { @@ -891,14 +888,16 @@ void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) { ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers); } -void BufferStateLayer::bufferMayChange(sp& newBuffer) { - if (mDrawingState.buffer != nullptr && mDrawingState.buffer != mBufferInfo.mBuffer && - newBuffer != mDrawingState.buffer) { +void BufferStateLayer::bufferMayChange(const sp& newBuffer) { + if (mDrawingState.buffer != nullptr && + (!mBufferInfo.mBuffer || + mDrawingState.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) && + newBuffer != mDrawingState.buffer->getBuffer()) { // If we are about to update mDrawingState.buffer but it has not yet latched // then we will drop a buffer and should decrement the pending buffer count and // call any release buffer callbacks if set. - callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer, - mDrawingState.acquireFence); + callReleaseBufferCallback(mDrawingState.releaseBufferListener, + mDrawingState.buffer->getBuffer(), mDrawingState.acquireFence); decrementPendingBufferCount(); } } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 8ce3e1f55b..a69d07f634 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -66,9 +66,9 @@ public: bool setTransform(uint32_t transform) override; bool setTransformToDisplayInverse(bool transformToDisplayInverse) override; bool setCrop(const Rect& crop) override; - bool setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, - nsecs_t desiredPresentTime, bool isAutoTimestamp, - const client_cache_t& clientCacheId, uint64_t frameNumber, + bool setBuffer(const std::shared_ptr& buffer, + const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, + bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, std::optional dequeueTime, const FrameTimelineInfo& info, const sp& transactionListener) override; bool setAcquireFence(const sp& fence) override; @@ -108,7 +108,7 @@ public: // See mPendingBufferTransactions void decrementPendingBufferCount(); - void bufferMayChange(sp& newBuffer) override; + void bufferMayChange(const sp& newBuffer) override; std::atomic* getPendingBufferCounter() override { return &mPendingBufferTransactions; } std::string getPendingBufferCounterName() override { return mBlastTransactionName; } diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp index 44b33ef43d..f310738423 100644 --- a/services/surfaceflinger/ClientCache.cpp +++ b/services/surfaceflinger/ClientCache.cpp @@ -102,7 +102,12 @@ bool ClientCache::add(const client_cache_t& cacheId, const sp& bu return false; } - processBuffers[id].buffer = buffer; + LOG_ALWAYS_FATAL_IF(mRenderEngine == nullptr, + "Attempted to build the ClientCache before a RenderEngine instance was " + "ready!"); + processBuffers[id].buffer = std::make_shared< + renderengine::ExternalTexture>(buffer, *mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE); return true; } @@ -132,7 +137,7 @@ void ClientCache::erase(const client_cache_t& cacheId) { } } -sp ClientCache::get(const client_cache_t& cacheId) { +std::shared_ptr ClientCache::get(const client_cache_t& cacheId) { std::lock_guard lock(mMutex); ClientCacheBuffer* buf = nullptr; @@ -213,8 +218,8 @@ void ClientCache::dump(std::string& result) { auto &buffers = i.second.second; for (auto& [id, clientCacheBuffer] : buffers) { StringAppendF(&result, "\t ID: %d, Width/Height: %d,%d\n", (int)id, - (int)clientCacheBuffer.buffer->getWidth(), - (int)clientCacheBuffer.buffer->getHeight()); + (int)clientCacheBuffer.buffer->getBuffer()->getWidth(), + (int)clientCacheBuffer.buffer->getBuffer()->getHeight()); } } } diff --git a/services/surfaceflinger/ClientCache.h b/services/surfaceflinger/ClientCache.h index 0d597c8e05..a9b8177d70 100644 --- a/services/surfaceflinger/ClientCache.h +++ b/services/surfaceflinger/ClientCache.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,11 @@ public: bool add(const client_cache_t& cacheId, const sp& buffer); void erase(const client_cache_t& cacheId); - sp get(const client_cache_t& cacheId); + std::shared_ptr get(const client_cache_t& cacheId); + + // Always called immediately after setup. Will be set to non-null, and then should never be + // called again. + void setRenderEngine(renderengine::RenderEngine* renderEngine) { mRenderEngine = renderEngine; } void removeProcess(const wp& processToken); @@ -59,7 +64,7 @@ private: std::mutex mMutex; struct ClientCacheBuffer { - sp buffer; + std::shared_ptr buffer; std::set> recipients; }; std::map /*caching process*/, @@ -73,6 +78,7 @@ private: }; sp mDeathRecipient; + renderengine::RenderEngine* mRenderEngine = nullptr; bool getBuffer(const client_cache_t& cacheId, ClientCacheBuffer** outClientCacheBuffer) REQUIRES(mMutex); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index f680460242..daee83bd2c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -16,15 +16,16 @@ #pragma once -#include -#include - +#include #include #include #include #include #include +#include +#include + namespace android { class GraphicBuffer; @@ -80,7 +81,8 @@ public: virtual void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) = 0; // Allocates a buffer as scratch space for GPU composition - virtual sp dequeueBuffer(base::unique_fd* bufferFence) = 0; + virtual std::shared_ptr dequeueBuffer( + base::unique_fd* bufferFence) = 0; // Queues the drawn buffer for consumption by HWC. readyFence is the fence // which will fire when the buffer is ready for consumption. diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h index a1230b3c4d..a8d372c562 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h @@ -45,6 +45,8 @@ struct RenderSurfaceCreationArgs { // The DisplaySurface for this surface sp displaySurface; + + size_t maxTextureCacheSize; }; /** @@ -81,6 +83,11 @@ public: return *this; } + RenderSurfaceCreationArgsBuilder& setMaxTextureCacheSize(size_t maxTextureCacheSize) { + mArgs.maxTextureCacheSize = maxTextureCacheSize; + return *this; + } + private: RenderSurfaceCreationArgs mArgs; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index 48a54d6c66..c61ec5991b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -89,7 +89,7 @@ struct OutputLayerCompositionState { // Overrides the buffer, acquire fence, and display frame stored in LayerFECompositionState struct { - sp buffer = nullptr; + std::shared_ptr buffer = nullptr; sp acquireFence = nullptr; Rect displayFrame = {}; ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index 5127a6f314..a8a538003e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -16,12 +16,16 @@ #pragma once -#include - #include #include #include +#include +#include + +#include "renderengine/ExternalTexture.h" +#include "renderengine/RenderEngine.h" + struct ANativeWindow; namespace android { @@ -54,7 +58,8 @@ public: void setProtected(bool useProtected) override; status_t beginFrame(bool mustRecompose) override; void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) override; - sp dequeueBuffer(base::unique_fd* bufferFence) override; + std::shared_ptr dequeueBuffer( + base::unique_fd* bufferFence) override; void queueBuffer(base::unique_fd readyFence) override; void onPresentDisplayCompleted() override; void flip() override; @@ -66,7 +71,7 @@ public: // Testing void setPageFlipCountForTest(std::uint32_t); void setSizeForTest(const ui::Size&); - sp& mutableGraphicBufferForTest(); + std::shared_ptr& mutableTextureForTest(); base::unique_fd& mutableBufferReadyForTest(); private: @@ -75,10 +80,13 @@ private: // ANativeWindow being rendered into const sp mNativeWindow; - // Current buffer being rendered into - sp mGraphicBuffer; + + std::vector> mTextureCache; + // Current texture being rendered into + std::shared_ptr mTexture; const sp mDisplaySurface; ui::Size mSize; + const size_t mMaxTextureCacheSize; bool mProtected{false}; std::uint32_t mPageFlipCount{0}; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h index c5d03a7218..53f4a30fb8 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h @@ -66,7 +66,7 @@ public: const Rect& getBounds() const { return mBounds; } const Region& getVisibleRegion() const { return mVisibleRegion; } size_t getAge() const { return mAge; } - const sp& getBuffer() const { return mTexture.getBuffer(); } + const std::shared_ptr& getBuffer() const { return mTexture; } const sp& getDrawFence() const { return mDrawFence; } const ProjectionSpace& getOutputSpace() const { return mOutputSpace; } ui::Dataspace getOutputDataspace() const { return mOutputDataspace; } @@ -87,7 +87,7 @@ public: void setLastUpdate(std::chrono::steady_clock::time_point now) { mLastUpdate = now; } void append(const CachedSet& other) { - mTexture.setBuffer(nullptr, nullptr); + mTexture = nullptr; mOutputDataspace = ui::Dataspace::UNKNOWN; mDrawFence = nullptr; @@ -115,31 +115,7 @@ private: Region mVisibleRegion; size_t mAge = 0; - class Texture { - public: - ~Texture() { setBuffer(nullptr, nullptr); } - - void setBuffer(const sp& buffer, renderengine::RenderEngine* re) { - if (mRE && mBuffer) { - mRE->unbindExternalTextureBuffer(mBuffer->getId()); - } - - mBuffer = buffer; - mRE = re; - - if (mRE && mBuffer) { - mRE->cacheExternalTextureBuffer(mBuffer); - } - } - - const sp& getBuffer() const { return mBuffer; } - - private: - sp mBuffer = nullptr; - renderengine::RenderEngine* mRE = nullptr; - }; - - Texture mTexture; + std::shared_ptr mTexture; sp mDrawFence; ProjectionSpace mOutputSpace; ui::Dataspace mOutputDataspace; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index a0cae6fcbb..fe858c2817 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -39,7 +39,7 @@ public: MOCK_METHOD1(setBufferPixelFormat, void(ui::PixelFormat)); MOCK_METHOD1(beginFrame, status_t(bool mustRecompose)); MOCK_METHOD2(prepareFrame, void(bool, bool)); - MOCK_METHOD1(dequeueBuffer, sp(base::unique_fd*)); + MOCK_METHOD1(dequeueBuffer, std::shared_ptr(base::unique_fd*)); MOCK_METHOD1(queueBuffer, void(base::unique_fd)); MOCK_METHOD0(onPresentDisplayCompleted, void()); MOCK_METHOD0(flip, void()); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 3ac5433457..3468b204fc 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -14,8 +14,7 @@ * limitations under the License. */ -#include - +#include #include #include #include @@ -29,7 +28,9 @@ #include #include -#include +#include + +#include "renderengine/ExternalTexture.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push @@ -715,11 +716,11 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr bool skipLayer = false; if (layer->getState().overrideInfo.buffer != nullptr) { if (previousOverride != nullptr && - layer->getState().overrideInfo.buffer == previousOverride) { + layer->getState().overrideInfo.buffer->getBuffer() == previousOverride) { ALOGV("Skipping redundant buffer"); skipLayer = true; } - previousOverride = layer->getState().overrideInfo.buffer; + previousOverride = layer->getState().overrideInfo.buffer->getBuffer(); } const bool includeGeometry = refreshArgs.updatingGeometryThisFrame; @@ -978,14 +979,15 @@ std::optional Output::composeSurfaces( } base::unique_fd fd; - sp buf; + + std::shared_ptr tex; // If we aren't doing client composition on this output, but do have a // flipClientTarget request for this frame on this output, we still need to // dequeue a buffer. if (hasClientComposition || outputState.flipClientTarget) { - buf = mRenderSurface->dequeueBuffer(&fd); - if (buf == nullptr) { + tex = mRenderSurface->dequeueBuffer(&fd); + if (tex == nullptr) { ALOGW("Dequeuing buffer for display [%s] failed, bailing out of " "client composition for this frame", mName.c_str()); @@ -1030,13 +1032,14 @@ std::optional Output::composeSurfaces( // Check if the client composition requests were rendered into the provided graphic buffer. If // so, we can reuse the buffer and avoid client composition. if (mClientCompositionRequestCache) { - if (mClientCompositionRequestCache->exists(buf->getId(), clientCompositionDisplay, + if (mClientCompositionRequestCache->exists(tex->getBuffer()->getId(), + clientCompositionDisplay, clientCompositionLayers)) { outputCompositionState.reusedClientComposition = true; setExpensiveRenderingExpected(false); return readyFence; } - mClientCompositionRequestCache->add(buf->getId(), clientCompositionDisplay, + mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay, clientCompositionLayers); } @@ -1069,12 +1072,12 @@ std::optional Output::composeSurfaces( // over to RenderEngine, in which case this flag can be removed from the drawLayers interface. const bool useFramebufferCache = outputState.layerStackInternal; status_t status = - renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buf, + renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex, useFramebufferCache, std::move(fd), &readyFence); if (status != NO_ERROR && mClientCompositionRequestCache) { // If rendering was not successful, remove the request from the cache. - mClientCompositionRequestCache->remove(buf->getId()); + mClientCompositionRequestCache->remove(tex->getBuffer()->getId()); } auto& timeStats = getCompositionEngine().getTimeStats(); @@ -1151,9 +1154,9 @@ std::vector Output::generateClientCompositionRequests( std::vector results; if (layer->getState().overrideInfo.buffer != nullptr) { - if (layer->getState().overrideInfo.buffer != previousOverrideBuffer) { + if (layer->getState().overrideInfo.buffer->getBuffer() != previousOverrideBuffer) { results = layer->getOverrideCompositionList(); - previousOverrideBuffer = layer->getState().overrideInfo.buffer; + previousOverrideBuffer = layer->getState().overrideInfo.buffer->getBuffer(); ALOGV("Replacing [%s] with override in RE", layer->getLayerFE().getDebugName()); } else { ALOGV("Skipping redundant override buffer for [%s] in RE", diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index f640f85bca..9ca8914deb 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -537,7 +537,7 @@ void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer, sp buffer = outputIndependentState.buffer; sp acquireFence = outputIndependentState.acquireFence; if (getState().overrideInfo.buffer != nullptr) { - buffer = getState().overrideInfo.buffer; + buffer = getState().overrideInfo.buffer->getBuffer(); acquireFence = getState().overrideInfo.acquireFence; } @@ -699,7 +699,7 @@ std::vector OutputLayer::getOverrideCompositionList() co settings.geometry = renderengine::Geometry{ .boundaries = boundaries.toFloatRect(), }; - settings.bufferId = getState().overrideInfo.buffer->getId(); + settings.bufferId = getState().overrideInfo.buffer->getBuffer()->getId(); settings.source = renderengine::PixelSource{ .buffer = renderengine::Buffer{ .buffer = getState().overrideInfo.buffer, diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 3bef77dde1..ef50870615 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -25,8 +25,8 @@ #include #include #include - #include +#include #include #include #include @@ -63,7 +63,8 @@ RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display mDisplay(display), mNativeWindow(args.nativeWindow), mDisplaySurface(args.displaySurface), - mSize(args.displayWidth, args.displayHeight) { + mSize(args.displayWidth, args.displayHeight), + mMaxTextureCacheSize(args.maxTextureCacheSize) { LOG_ALWAYS_FATAL_IF(!mNativeWindow); } @@ -146,7 +147,8 @@ void RenderSurface::prepareFrame(bool usesClientComposition, bool usesDeviceComp } } -sp RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) { +std::shared_ptr RenderSurface::dequeueBuffer( + base::unique_fd* bufferFence) { ATRACE_CALL(); int fd = -1; ANativeWindowBuffer* buffer = nullptr; @@ -158,16 +160,41 @@ sp RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) { mDisplay.getName().c_str(), result); // Return fast here as we can't do much more - any rendering we do // now will just be wrong. - return mGraphicBuffer; + return mTexture; + } + + ALOGW_IF(mTexture != nullptr, "Clobbering a non-null pointer to a buffer [%p].", + mTexture->getBuffer()->getNativeBuffer()->handle); + + sp newBuffer = GraphicBuffer::from(buffer); + + std::shared_ptr texture; + + for (auto it = mTextureCache.begin(); it != mTextureCache.end(); it++) { + const auto& cachedTexture = *it; + if (cachedTexture->getBuffer()->getId() == newBuffer->getId()) { + texture = cachedTexture; + mTextureCache.erase(it); + break; + } } - ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].", - mGraphicBuffer->getNativeBuffer()->handle); - mGraphicBuffer = GraphicBuffer::from(buffer); + if (texture) { + mTexture = texture; + } else { + mTexture = std::make_shared< + renderengine::ExternalTexture>(GraphicBuffer::from(buffer), + mCompositionEngine.getRenderEngine(), + renderengine::ExternalTexture::Usage::WRITEABLE); + } + mTextureCache.push_back(mTexture); + if (mTextureCache.size() > mMaxTextureCacheSize) { + mTextureCache.erase(mTextureCache.begin()); + } *bufferFence = base::unique_fd(fd); - return mGraphicBuffer; + return mTexture; } void RenderSurface::queueBuffer(base::unique_fd readyFence) { @@ -177,24 +204,24 @@ void RenderSurface::queueBuffer(base::unique_fd readyFence) { // hasFlipClientTargetRequest could return true even if we haven't // dequeued a buffer before. Try dequeueing one if we don't have a // buffer ready. - if (mGraphicBuffer == nullptr) { + if (mTexture == nullptr) { ALOGI("Attempting to queue a client composited buffer without one " "previously dequeued for display [%s]. Attempting to dequeue " "a scratch buffer now", mDisplay.getName().c_str()); - // We shouldn't deadlock here, since mGraphicBuffer == nullptr only + // We shouldn't deadlock here, since mTexture == nullptr only // after a successful call to queueBuffer, or if dequeueBuffer has // never been called. base::unique_fd unused; dequeueBuffer(&unused); } - if (mGraphicBuffer == nullptr) { + if (mTexture == nullptr) { ALOGE("No buffer is ready for display [%s]", mDisplay.getName().c_str()); } else { - status_t result = - mNativeWindow->queueBuffer(mNativeWindow.get(), - mGraphicBuffer->getNativeBuffer(), dup(readyFence)); + status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(), + mTexture->getBuffer()->getNativeBuffer(), + dup(readyFence)); if (result != NO_ERROR) { ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(), result); @@ -204,11 +231,12 @@ void RenderSurface::queueBuffer(base::unique_fd readyFence) { LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result); } else { mNativeWindow->cancelBuffer(mNativeWindow.get(), - mGraphicBuffer->getNativeBuffer(), dup(readyFence)); + mTexture->getBuffer()->getNativeBuffer(), + dup(readyFence)); } } - mGraphicBuffer = nullptr; + mTexture = nullptr; } } @@ -256,8 +284,8 @@ void RenderSurface::setSizeForTest(const ui::Size& size) { mSize = size; } -sp& RenderSurface::mutableGraphicBufferForTest() { - return mGraphicBuffer; +std::shared_ptr& RenderSurface::mutableTextureForTest() { + return mTexture; } } // namespace impl diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index dcb75556e3..53557bbb9f 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -130,7 +130,7 @@ bool CachedSet::hasBufferUpdate() const { } bool CachedSet::hasReadyBuffer() const { - return mTexture.getBuffer() != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled; + return mTexture != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled; } std::vector CachedSet::decompose() const { @@ -217,21 +217,27 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, sp buffer = new GraphicBuffer(static_cast(mBounds.getWidth()), static_cast(mBounds.getHeight()), HAL_PIXEL_FORMAT_RGBA_8888, 1, usageFlags); + const auto texture = std::make_shared< + renderengine::ExternalTexture>(buffer, renderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); LOG_ALWAYS_FATAL_IF(buffer->initCheck() != OK); base::unique_fd drawFence; - status_t result = renderEngine.drawLayers(displaySettings, layerSettingsPointers, buffer, false, - base::unique_fd(), &drawFence); + status_t result = renderEngine.drawLayers(displaySettings, layerSettingsPointers, mTexture, + false, base::unique_fd(), &drawFence); if (result == NO_ERROR) { - mTexture.setBuffer(buffer, &renderEngine); mDrawFence = new Fence(drawFence.release()); mOutputSpace = ProjectionSpace(ui::Size(outputState.framebufferSpace.bounds.getWidth(), outputState.framebufferSpace.bounds.getHeight()), mBounds); + mTexture = std::move(texture); mOutputSpace.orientation = outputState.framebufferSpace.orientation; mOutputDataspace = outputDataspace; mOrientation = orientation; + } else { + mTexture = nullptr; } } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp index ad7555730d..3a2534b847 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp @@ -111,7 +111,12 @@ void Planner::reportFinalPlan( const GraphicBuffer* currentOverrideBuffer = nullptr; bool hasSkippedLayers = false; for (auto layer : layers) { - const GraphicBuffer* overrideBuffer = layer->getState().overrideInfo.buffer.get(); + if (!layer->getState().overrideInfo.buffer) { + continue; + } + + const GraphicBuffer* overrideBuffer = + layer->getState().overrideInfo.buffer->getBuffer().get(); if (overrideBuffer != nullptr && overrideBuffer == currentOverrideBuffer) { // Skip this layer since it is part of a previous cached set hasSkippedLayers = true; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 8a4d161289..4c3f4940cc 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -26,6 +26,7 @@ #include "MockHWC2.h" #include "MockHWComposer.h" #include "RegionMatcher.h" +#include "renderengine/mock/RenderEngine.h" namespace android::compositionengine { namespace { @@ -715,7 +716,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static const HdrMetadata kHdrMetadata; static native_handle_t* kSidebandStreamHandle; static const sp kBuffer; - static const sp kOverrideBuffer; + std::shared_ptr kOverrideBuffer; static const sp kFence; static const sp kOverrideFence; static const std::string kLayerGenericMetadata1Key; @@ -724,6 +725,11 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static const std::vector kLayerGenericMetadata2Value; OutputLayerWriteStateToHWCTest() { + kOverrideBuffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage:: + WRITEABLE); auto& outputLayerState = mOutputLayer.editState(); outputLayerState.hwc = impl::OutputLayerCompositionState::Hwc(mHwcLayer); @@ -839,6 +845,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { std::shared_ptr mHwcLayer{std::make_shared>()}; StrictMock mDisplayColorProfile; + renderengine::mock::RenderEngine mRenderEngine; }; const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 83.f / 255.f, @@ -858,7 +865,6 @@ const HdrMetadata OutputLayerWriteStateToHWCTest::kHdrMetadata{{/* LightFlattena native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle = reinterpret_cast(1031); const sp OutputLayerWriteStateToHWCTest::kBuffer; -const sp OutputLayerWriteStateToHWCTest::kOverrideBuffer = new GraphicBuffer(); const sp OutputLayerWriteStateToHWCTest::kFence; const sp OutputLayerWriteStateToHWCTest::kOverrideFence = new Fence(); const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key = @@ -1023,7 +1029,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { kOverrideBufferTransform, kOverrideBlendMode, kOverrideAlpha); expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion, kOverrideSurfaceDamage); - expectSetHdrMetadataAndBufferCalls(kOverrideBuffer, kOverrideFence); + expectSetHdrMetadataAndBufferCalls(kOverrideBuffer->getBuffer(), kOverrideFence); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 5f0b0eea15..e80100cc6e 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#include - #include #include #include @@ -31,9 +29,12 @@ #include #include +#include + #include "CallOrderStateMachineHelper.h" #include "MockHWC2.h" #include "RegionMatcher.h" +#include "renderengine/ExternalTexture.h" namespace android::compositionengine { namespace { @@ -2960,7 +2961,10 @@ struct OutputComposeSurfacesTest : public testing::Test { mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock(); mock::RenderSurface* mRenderSurface = new StrictMock(); StrictMock mOutput; - sp mOutputBuffer = new GraphicBuffer(); + std::shared_ptr mOutputBuffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); std::optional mReadyFence; }; @@ -3173,7 +3177,10 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) { EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _)) .WillRepeatedly(Return()); - sp otherOutputBuffer = new GraphicBuffer(); + const auto otherOutputBuffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)) .WillOnce(Return(mOutputBuffer)) .WillOnce(Return(otherOutputBuffer)); diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 5ef5d7b5cb..9aeb290eb5 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -15,6 +15,8 @@ */ // TODO(b/129481165): remove the #pragma below and fix conversion issues +#include "renderengine/ExternalTexture.h" +#include "ui/GraphicBuffer.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wextra" @@ -239,9 +241,9 @@ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) { DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR))); base::unique_fd fence; - EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer(&fence).get()); + EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer(&fence)->getBuffer().get()); - EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(buffer.get(), mSurface.mutableTextureForTest()->getBuffer().get()); } /* @@ -249,8 +251,11 @@ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) { */ TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { - sp buffer = new GraphicBuffer(); - mSurface.mutableGraphicBufferForTest() = buffer; + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); + mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = false; @@ -261,43 +266,45 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(buffer.get(), mSurface.mutableTextureForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) { - sp buffer = new GraphicBuffer(); - mSurface.mutableGraphicBufferForTest() = buffer; + const auto buffer = std::make_shared(new GraphicBuffer(), + mRenderEngine, false); + mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = true; state.flipClientTarget = false; EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); - EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) { - sp buffer = new GraphicBuffer(); - mSurface.mutableGraphicBufferForTest() = buffer; + const auto buffer = std::make_shared(new GraphicBuffer(), + mRenderEngine, false); + mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = false; state.flipClientTarget = true; EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); - EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) { @@ -317,27 +324,28 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferY mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) { - sp buffer = new GraphicBuffer(); - mSurface.mutableGraphicBufferForTest() = buffer; + const auto buffer = std::make_shared(new GraphicBuffer(), + mRenderEngine, false); + mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = true; EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); - EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) .WillOnce(Return(INVALID_OPERATION)); EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true)); - EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index f01fe27b38..283c69270f 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -305,8 +305,8 @@ TEST_F(CachedSetTest, render) { const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, const std::vector& layers, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> size_t { + const std::shared_ptr&, const bool, + base::unique_fd&&, base::unique_fd*) -> size_t { EXPECT_EQ(Rect(0, 0, 2, 2), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation), @@ -321,7 +321,6 @@ TEST_F(CachedSetTest, render) { EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1)); EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers)); - EXPECT_CALL(mRenderEngine, cacheExternalTextureBuffer(_)); cachedSet.render(mRenderEngine, mOutputState); expectReadyBuffer(cachedSet); @@ -331,7 +330,6 @@ TEST_F(CachedSetTest, render) { cachedSet.getOutputSpace().bounds); // Now check that appending a new cached set properly cleans up RenderEngine resources. - EXPECT_CALL(mRenderEngine, unbindExternalTextureBuffer(_)); CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get(); cachedSet.append(CachedSet(layer3)); } diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index b7b2cc691b..8692ee60dc 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -70,11 +70,13 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) mIsPrimary(args.isPrimary) { mCompositionDisplay->editState().isSecure = args.isSecure; mCompositionDisplay->createRenderSurface( - compositionengine::RenderSurfaceCreationArgs{ANativeWindow_getWidth( - args.nativeWindow.get()), - ANativeWindow_getHeight( - args.nativeWindow.get()), - args.nativeWindow, args.displaySurface}); + compositionengine:: + RenderSurfaceCreationArgs{ANativeWindow_getWidth(args.nativeWindow.get()), + ANativeWindow_getHeight(args.nativeWindow.get()), + args.nativeWindow, args.displaySurface, + static_cast( + SurfaceFlinger:: + maxFrameBufferAcquiredBuffers)}); if (!mFlinger->mDisableClientCompositionCache && SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 829b91676b..b12e3fb626 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1050,7 +1050,7 @@ uint32_t Layer::doTransaction(uint32_t flags) { } // Allow BufferStateLayer to release any unlatched buffers in drawing state. - bufferMayChange(c.buffer); + bufferMayChange(c.buffer->getBuffer()); // Commit the transaction commitTransaction(c); @@ -1062,7 +1062,11 @@ uint32_t Layer::doTransaction(uint32_t flags) { void Layer::commitTransaction(State& stateToCommit) { if (auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX; - mDrawingState.buffer != stateToCommit.buffer && bufferSurfaceFrame != nullptr && + ((mDrawingState.buffer && stateToCommit.buffer && + mDrawingState.buffer->getBuffer() != stateToCommit.buffer->getBuffer()) || + (mDrawingState.buffer && !stateToCommit.buffer) || + (!mDrawingState.buffer && stateToCommit.buffer)) && + bufferSurfaceFrame != nullptr && bufferSurfaceFrame->getPresentState() != PresentState::Presented) { // If the previous buffer was committed but not latched (refreshPending - happens during // back to back invalidates), it gets silently dropped here. Mark the corresponding diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 64986afd61..8e51e4139b 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -208,7 +208,7 @@ public: Region transparentRegionHint; - sp buffer; + std::shared_ptr buffer; client_cache_t clientCacheId; sp acquireFence; std::shared_ptr acquireFenceTime; @@ -412,10 +412,11 @@ public: // Used only to set BufferStateLayer state virtual bool setTransform(uint32_t /*transform*/) { return false; }; virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; }; - virtual bool setBuffer(const sp& /*buffer*/, const sp& /*acquireFence*/, - nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, - bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/, - uint64_t /* frameNumber */, std::optional /* dequeueTime */, + virtual bool setBuffer(const std::shared_ptr& /*buffer*/, + const sp& /*acquireFence*/, nsecs_t /*postTime*/, + nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, + const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */, + std::optional /* dequeueTime */, const FrameTimelineInfo& /*info*/, const sp& /* releaseBufferListener */) { return false; @@ -726,7 +727,7 @@ public: * Called before updating the drawing state buffer. Used by BufferStateLayer to release any * unlatched buffers in the drawing state. */ - virtual void bufferMayChange(sp& /* newBuffer */){}; + virtual void bufferMayChange(const sp& /* newBuffer */){}; /* * Remove relative z for the layer if its relative parent is not part of the diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 7a3e433660..a9fd16cb75 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -208,7 +208,8 @@ bool RefreshRateOverlay::createLayer() { return true; } -const std::vector>& RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { +const std::vector>& +RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { if (mBufferCache.find(fps) == mBufferCache.end()) { // Ensure the range is > 0, so we don't divide by 0. const auto rangeLength = std::max(1u, mHighFps - mLowFps); @@ -222,7 +223,17 @@ const std::vector>& RefreshRateOverlay::getOrCreateBuffers(uin color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale); color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale); color.a = ALPHA; - mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner)); + auto buffers = SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner); + std::vector> textures; + std::transform(buffers.begin(), buffers.end(), std::back_inserter(textures), + [&](const auto& buffer) -> std::shared_ptr { + return std::make_shared< + renderengine::ExternalTexture>(buffer, + mFlinger.getRenderEngine(), + renderengine::ExternalTexture:: + Usage::READABLE); + }); + mBufferCache.emplace(fps, textures); } return mBufferCache[fps]; diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index c16cfa07a4..aa8329c46a 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -16,13 +16,14 @@ #pragma once -#include - #include +#include #include #include #include +#include + #include "Fps.h" namespace android { @@ -70,7 +71,8 @@ private: }; bool createLayer(); - const std::vector>& getOrCreateBuffers(uint32_t fps); + const std::vector>& getOrCreateBuffers( + uint32_t fps); SurfaceFlinger& mFlinger; const sp mClient; @@ -78,7 +80,8 @@ private: sp mIBinder; sp mGbp; - std::unordered_map>> mBufferCache; + std::unordered_map>> + mBufferCache; std::optional mCurrentFps; int mFrame = 0; static constexpr float ALPHA = 0.8f; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index d0032ac7fd..00090d948a 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -438,18 +438,22 @@ void RegionSamplingThread::captureSample() { mFlinger.traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, filterVisitor); }; - sp buffer = nullptr; - if (mCachedBuffer && mCachedBuffer->getWidth() == sampledBounds.getWidth() && - mCachedBuffer->getHeight() == sampledBounds.getHeight()) { + std::shared_ptr buffer = nullptr; + if (mCachedBuffer && mCachedBuffer->getBuffer()->getWidth() == sampledBounds.getWidth() && + mCachedBuffer->getBuffer()->getHeight() == sampledBounds.getHeight()) { buffer = mCachedBuffer; } else { const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), - PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); - const status_t bufferStatus = buffer->initCheck(); + sp graphicBuffer = + new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), + PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); + const status_t bufferStatus = graphicBuffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d", bufferStatus); + buffer = std::make_shared< + renderengine::ExternalTexture>(graphicBuffer, mFlinger.getRenderEngine(), + renderengine::ExternalTexture::Usage::WRITEABLE); } const sp captureListener = new SyncScreenCaptureListener(); @@ -465,8 +469,8 @@ void RegionSamplingThread::captureSample() { } ALOGV("Sampling %zu descriptors", activeDescriptors.size()); - std::vector lumas = - sampleBuffer(buffer, sampledBounds.leftTop(), activeDescriptors, orientation); + std::vector lumas = sampleBuffer(buffer->getBuffer(), sampledBounds.leftTop(), + activeDescriptors, orientation); if (lumas.size() != activeDescriptors.size()) { ALOGW("collected %zu median luma values for %zu descriptors", lumas.size(), activeDescriptors.size()); @@ -477,16 +481,6 @@ void RegionSamplingThread::captureSample() { activeDescriptors[d].listener->onSampleCollected(lumas[d]); } - // Extend the lifetime of mCachedBuffer from the previous frame to here to ensure that: - // 1) The region sampling thread is the last owner of the buffer, and the freeing of the buffer - // happens in this thread, as opposed to the main thread. - // 2) The listener(s) receive their notifications prior to freeing the buffer. - if (mCachedBuffer != nullptr && mCachedBuffer != buffer) { - if (mFlinger.getRenderEngine().getRenderEngineType() == - renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) { - mFlinger.getRenderEngine().unbindExternalTextureBuffer(mCachedBuffer->getId()); - } - } mCachedBuffer = buffer; ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::noWorkNeeded)); } diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h index 0defdb3fcb..86632db490 100644 --- a/services/surfaceflinger/RegionSamplingThread.h +++ b/services/surfaceflinger/RegionSamplingThread.h @@ -16,17 +16,19 @@ #pragma once +#include +#include +#include +#include +#include +#include + #include #include #include #include #include -#include -#include -#include -#include -#include #include "Scheduler/OneShotTimer.h" namespace android { @@ -122,7 +124,8 @@ private: std::mutex mSamplingMutex; std::unordered_map, Descriptor, WpHash> mDescriptors GUARDED_BY(mSamplingMutex); - sp mCachedBuffer GUARDED_BY(mSamplingMutex) = nullptr; + std::shared_ptr mCachedBuffer GUARDED_BY(mSamplingMutex) = + nullptr; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 02579c6bde..e66f65b71e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -735,6 +735,7 @@ void SurfaceFlinger::init() { mCompositionEngine->setTimeStats(mTimeStats); mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName)); mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId); + ClientCache::getInstance().setRenderEngine(&getRenderEngine()); // Process any initial hotplug and resulting display changes. processDisplayHotplugEventsLocked(); const auto display = getDefaultDisplayDeviceLocked(); @@ -3707,7 +3708,6 @@ void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin if (uncacheBuffer.isValid()) { ClientCache::getInstance().erase(uncacheBuffer); - getRenderEngine().unbindExternalTextureBuffer(uncacheBuffer.id); } // If a synchronous transaction is explicitly requested without any changes, force a transaction @@ -4083,23 +4083,16 @@ uint32_t SurfaceFlinger::setClientStateLocked( } bool bufferChanged = what & layer_state_t::eBufferChanged; bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged; - sp buffer; + std::shared_ptr buffer; if (bufferChanged && cacheIdChanged && s.buffer != nullptr) { - buffer = s.buffer; - bool success = ClientCache::getInstance().add(s.cachedBuffer, s.buffer); - if (success) { - getRenderEngine().cacheExternalTextureBuffer(s.buffer); - success = ClientCache::getInstance() - .registerErasedRecipient(s.cachedBuffer, - wp(this)); - if (!success) { - getRenderEngine().unbindExternalTextureBuffer(s.buffer->getId()); - } - } + ClientCache::getInstance().add(s.cachedBuffer, s.buffer); + buffer = ClientCache::getInstance().get(s.cachedBuffer); } else if (cacheIdChanged) { buffer = ClientCache::getInstance().get(s.cachedBuffer); } else if (bufferChanged) { - buffer = s.buffer; + buffer = std::make_shared< + renderengine::ExternalTexture>(s.buffer, getRenderEngine(), + renderengine::ExternalTexture::Usage::READABLE); } if (buffer) { const bool frameNumberChanged = what & layer_state_t::eFrameNumberChanged; @@ -6003,15 +5996,17 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, const status_t bufferStatus = buffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d", bufferStatus); - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, + const auto texture = std::make_shared< + renderengine::ExternalTexture>(buffer, getRenderEngine(), + renderengine::ExternalTexture::Usage::WRITEABLE); + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, texture, false /* regionSampling */, grayscale, captureListener); } -status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, - TraverseLayersFunction traverseLayers, - sp& buffer, bool regionSampling, - bool grayscale, - const sp& captureListener) { +status_t SurfaceFlinger::captureScreenCommon( + RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, + const std::shared_ptr& buffer, bool regionSampling, + bool grayscale, const sp& captureListener) { ATRACE_CALL(); if (captureListener == nullptr) { @@ -6044,15 +6039,6 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, regionSampling, grayscale, captureResults); }); - // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine - // Only do this when we're not doing region sampling, to allow the region sampling thread to - // manage buffer lifecycle itself. - if (!regionSampling && - getRenderEngine().getRenderEngineType() == - renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) { - getRenderEngine().unbindExternalTextureBuffer(buffer->getId()); - } - captureResults.result = result; captureListener->onScreenCaptureCompleted(captureResults); })); @@ -6060,11 +6046,10 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, return NO_ERROR; } -status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, - TraverseLayersFunction traverseLayers, - const sp& buffer, bool forSystem, - bool regionSampling, bool grayscale, - ScreenCaptureResults& captureResults) { +status_t SurfaceFlinger::renderScreenImplLocked( + const RenderArea& renderArea, TraverseLayersFunction traverseLayers, + const std::shared_ptr& buffer, bool forSystem, + bool regionSampling, bool grayscale, ScreenCaptureResults& captureResults) { ATRACE_CALL(); traverseLayers([&](Layer* layer) { @@ -6072,7 +6057,7 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure()); }); - const bool useProtected = buffer->getUsage() & GRALLOC_USAGE_PROTECTED; + const bool useProtected = buffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED; // We allow the system server to take screenshots of secure layers for // use in situations like the Screen-rotation animation and place @@ -6082,7 +6067,7 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, return PERMISSION_DENIED; } - captureResults.buffer = buffer; + captureResults.buffer = buffer->getBuffer(); captureResults.capturedDataspace = renderArea.getReqDataSpace(); const auto reqWidth = renderArea.getReqWidth(); @@ -6173,11 +6158,9 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, base::unique_fd drawFence; getRenderEngine().useProtectedContext(useProtected); - // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine - const bool useFramebufferCache = getRenderEngine().getRenderEngineType() == - renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED; + const constexpr bool kUseFramebufferCache = false; getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer, - useFramebufferCache, std::move(bufferFence), &drawFence); + kUseFramebufferCache, std::move(bufferFence), &drawFence); if (drawFence >= 0) { sp releaseFence = new Fence(dup(drawFence)); @@ -6442,10 +6425,6 @@ void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) { mOffscreenLayers.erase(layer); } -void SurfaceFlinger::bufferErased(const client_cache_t& clientCacheId) { - getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id); -} - status_t SurfaceFlinger::setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b3da61e810..a242d8a876 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -184,7 +184,6 @@ public: class SurfaceFlinger : public BnSurfaceComposer, public PriorityDumper, - public ClientCache::ErasedRecipient, private IBinder::DeathRecipient, private HWC2::ComposerCallback, private ISchedulerCallback { @@ -332,9 +331,6 @@ public: wp fromHandle(const sp& handle); wp fromHandleLocked(const sp& handle) const REQUIRES(mStateLock); - // Inherit from ClientCache::ErasedRecipient - void bufferErased(const client_cache_t& clientCacheId) override; - // If set, disables reusing client composition buffers. This can be set by // debug.sf.disable_client_composition_cache bool mDisableClientCompositionCache = false; @@ -907,12 +903,14 @@ private: status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, ui::PixelFormat, bool allowProtected, bool grayscale, const sp&); - status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp&, + status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, + const std::shared_ptr&, bool regionSampling, bool grayscale, const sp&); status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction, - const sp&, bool forSystem, bool regionSampling, - bool grayscale, ScreenCaptureResults&); + const std::shared_ptr&, + bool forSystem, bool regionSampling, bool grayscale, + ScreenCaptureResults&); sp getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); sp getDisplayById(DisplayId displayId) const REQUIRES(mStateLock); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 4e1c0c77ea..3042450f29 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -15,6 +15,7 @@ */ // TODO(b/129481165): remove the #pragma below and fix conversion issues +#include "renderengine/ExternalTexture.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wextra" @@ -194,7 +195,7 @@ public: sp mClientTargetAcquireFence = Fence::NO_FENCE; - sp mCaptureScreenBuffer; + std::shared_ptr mCaptureScreenBuffer; }; template @@ -243,11 +244,15 @@ void CompositionTest::captureScreenComposition() { // TODO: Eliminate expensive/real allocation if possible. const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - mCaptureScreenBuffer = new GraphicBuffer(renderArea->getReqWidth(), renderArea->getReqHeight(), - HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot"); + mCaptureScreenBuffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(renderArea->getReqWidth(), + renderArea->getReqHeight(), + HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, + "screenshot"), + *mRenderEngine, true); status_t result = - mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer.get(), + mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer, forSystem, regionSampling); EXPECT_EQ(NO_ERROR, result); @@ -340,8 +345,8 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings, const std::vector&, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr&, + const bool, base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -389,8 +394,8 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings, const std::vector&, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr&, + const bool, base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -625,8 +630,8 @@ struct BaseLayerProperties { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings& displaySettings, const std::vector& layerSettings, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr&, const bool, + base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -674,8 +679,8 @@ struct BaseLayerProperties { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings& displaySettings, const std::vector& layerSettings, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr&, const bool, + base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -751,8 +756,8 @@ struct CommonSecureLayerProperties : public BaseLayerProperties EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings& displaySettings, const std::vector& layerSettings, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr&, const bool, + base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 63baf7dee2..d004b9d9eb 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -352,8 +352,8 @@ public: auto renderScreenImplLocked(const RenderArea& renderArea, SurfaceFlinger::TraverseLayersFunction traverseLayers, - const sp& buffer, bool forSystem, - bool regionSampling) { + const std::shared_ptr& buffer, + bool forSystem, bool regionSampling) { ScreenCaptureResults captureResults; return mFlinger->renderScreenImplLocked(renderArea, traverseLayers, buffer, forSystem, regionSampling, false /* grayscale */, diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index b5ef0a1334..690a7fd757 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include "TestableSurfaceFlinger.h" @@ -102,6 +104,7 @@ public: TestableSurfaceFlinger mFlinger; Hwc2::mock::Composer* mComposer = nullptr; + renderengine::mock::RenderEngine mRenderEngine; FenceToFenceTimeMap fenceFactory; client_cache_t mClientCache; @@ -109,9 +112,12 @@ public: sp layer = createBufferStateLayer(); sp fence(new Fence()); - sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); int32_t layerId = layer->getSequence(); - uint64_t bufferId = buffer->getId(); + uint64_t bufferId = buffer->getBuffer()->getId(); uint64_t frameNumber = 5; nsecs_t dequeueTime = 10; nsecs_t postTime = 20; diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index c75538f476..6ff6e908fa 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include "TestableSurfaceFlinger.h" @@ -104,6 +106,7 @@ public: TestableSurfaceFlinger mFlinger; Hwc2::mock::Composer* mComposer = nullptr; + renderengine::mock::RenderEngine mRenderEngine; FenceToFenceTimeMap fenceFactory; client_cache_t mClientCache; @@ -124,7 +127,10 @@ public: sp layer = createBufferStateLayer(); sp fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence->signalForTest(12); @@ -149,7 +155,10 @@ public: sp fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer1 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -158,7 +167,10 @@ public: sp fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - sp buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer2 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); nsecs_t start = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); @@ -196,8 +208,10 @@ public: sp fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; - + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence->signalForTest(12); @@ -222,8 +236,10 @@ public: sp layer = createBufferStateLayer(); sp fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; - + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -252,8 +268,10 @@ public: sp fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; - + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -351,7 +369,10 @@ public: sp fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer1 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); @@ -359,7 +380,10 @@ public: sp fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - sp buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer2 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence2->signalForTest(12); @@ -386,7 +410,10 @@ public: sp fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer1 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -395,7 +422,10 @@ public: sp fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - sp buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer2 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); auto dropStartTime1 = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0}, @@ -407,7 +437,10 @@ public: sp fence3(new Fence()); auto acquireFence3 = fenceFactory.createFenceTimeForTest(fence3); - sp buffer3{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer3 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); auto dropStartTime2 = systemTime(); layer->setBuffer(buffer3, fence3, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); @@ -447,7 +480,11 @@ public: std::vector> bufferlessSurfaceFrames; for (int i = 0; i < 10; i += 2) { sp fence1(new Fence()); - sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer1 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + 0), + mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); -- cgit v1.2.3-59-g8ed1b From 617752fa9590d39930f7bcf46abaea8f2e1e1032 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 15 Apr 2021 16:27:01 +0000 Subject: Revert "Add ExternalTexture class into RenderEngine interface" Revert submission 14086921-renderengine-external-tex Reason for revert: Potential culprit for b/185361988 Reverted Changes: I7796764e2:Update WaylandRenderSurface to accomodate interfac... I13904eec4:Update Readback VTS to align with RenderEngine int... I222c71e6e:Add ExternalTexture class into RenderEngine interf... Change-Id: I1501890f4861a3df7ce273f1fe2ccdb275e2632c --- libs/renderengine/Android.bp | 1 - libs/renderengine/ExternalTexture.cpp | 43 ---- libs/renderengine/gl/GLESRenderEngine.cpp | 30 ++- libs/renderengine/gl/GLESRenderEngine.h | 11 +- .../include/renderengine/ExternalTexture.h | 61 ------ .../include/renderengine/LayerSettings.h | 8 +- .../include/renderengine/RenderEngine.h | 57 +++--- .../include/renderengine/mock/RenderEngine.h | 9 +- libs/renderengine/skia/AutoBackendTexture.h | 15 +- libs/renderengine/skia/Cache.cpp | 47 ++--- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 110 +++++----- libs/renderengine/skia/SkiaGLRenderEngine.h | 16 +- libs/renderengine/skia/SkiaRenderEngine.h | 10 +- libs/renderengine/tests/RenderEngineTest.cpp | 228 ++++++++++++++------- .../tests/RenderEngineThreadedTest.cpp | 9 +- .../renderengine/threaded/RenderEngineThreaded.cpp | 15 +- libs/renderengine/threaded/RenderEngineThreaded.h | 11 +- services/surfaceflinger/BufferLayer.cpp | 38 ++-- services/surfaceflinger/BufferLayer.h | 2 +- services/surfaceflinger/BufferLayerConsumer.cpp | 56 +++-- services/surfaceflinger/BufferLayerConsumer.h | 12 +- services/surfaceflinger/BufferStateLayer.cpp | 57 +++--- services/surfaceflinger/BufferStateLayer.h | 8 +- services/surfaceflinger/ClientCache.cpp | 13 +- services/surfaceflinger/ClientCache.h | 10 +- .../include/compositionengine/RenderSurface.h | 10 +- .../compositionengine/RenderSurfaceCreationArgs.h | 7 - .../impl/OutputLayerCompositionState.h | 4 +- .../include/compositionengine/impl/RenderSurface.h | 20 +- .../compositionengine/impl/planner/CachedSet.h | 30 ++- .../include/compositionengine/mock/RenderSurface.h | 2 +- .../CompositionEngine/src/Output.cpp | 31 ++- .../CompositionEngine/src/OutputLayer.cpp | 4 +- .../CompositionEngine/src/RenderSurface.cpp | 64 ++---- .../CompositionEngine/src/planner/CachedSet.cpp | 14 +- .../CompositionEngine/src/planner/Planner.cpp | 7 +- .../CompositionEngine/tests/OutputLayerTest.cpp | 12 +- .../CompositionEngine/tests/OutputTest.cpp | 15 +- .../CompositionEngine/tests/RenderSurfaceTest.cpp | 46 ++--- .../tests/planner/CachedSetTest.cpp | 6 +- services/surfaceflinger/DisplayDevice.cpp | 12 +- services/surfaceflinger/Layer.cpp | 8 +- services/surfaceflinger/Layer.h | 13 +- services/surfaceflinger/RefreshRateOverlay.cpp | 15 +- services/surfaceflinger/RefreshRateOverlay.h | 11 +- services/surfaceflinger/RegionSamplingThread.cpp | 30 +-- services/surfaceflinger/RegionSamplingThread.h | 15 +- services/surfaceflinger/SurfaceFlinger.cpp | 67 +++--- services/surfaceflinger/SurfaceFlinger.h | 12 +- .../tests/unittests/CompositionTest.cpp | 33 ++- .../tests/unittests/TestableSurfaceFlinger.h | 4 +- .../tests/unittests/TransactionFrameTracerTest.cpp | 10 +- .../unittests/TransactionSurfaceFrameTest.cpp | 67 ++---- 53 files changed, 643 insertions(+), 803 deletions(-) delete mode 100644 libs/renderengine/ExternalTexture.cpp delete mode 100644 libs/renderengine/include/renderengine/ExternalTexture.h (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index f395ab43d8..ec39137e24 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -48,7 +48,6 @@ filegroup { name: "librenderengine_sources", srcs: [ "Description.cpp", - "ExternalTexture.cpp", "Mesh.cpp", "RenderEngine.cpp", "Texture.cpp", diff --git a/libs/renderengine/ExternalTexture.cpp b/libs/renderengine/ExternalTexture.cpp deleted file mode 100644 index eabff58eba..0000000000 --- a/libs/renderengine/ExternalTexture.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include - -#include "log/log_main.h" - -namespace android::renderengine { - -ExternalTexture::ExternalTexture(const sp& buffer, RenderEngine& renderEngine, - uint32_t usage) - : mBuffer(buffer), mRenderEngine(renderEngine) { - LOG_ALWAYS_FATAL_IF(buffer == nullptr, - "Attempted to bind a null buffer to an external texture!"); - // GLESRenderEngine has a separate texture cache for output buffers, - if (usage == Usage::WRITEABLE && - (mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::GLES || - mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::THREADED)) { - return; - } - mRenderEngine.mapExternalTextureBuffer(mBuffer, usage & Usage::WRITEABLE); -} - -ExternalTexture::~ExternalTexture() { - mRenderEngine.unmapExternalTextureBuffer(mBuffer); -} - -} // namespace android::renderengine diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index d87315fdc2..a2963a7c33 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -746,8 +746,7 @@ void GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, const sp& buffer, - bool /*isRenderable*/) { +void GLESRenderEngine::cacheExternalTextureBuffer(const sp& buffer) { ATRACE_CALL(); mImageManager->cacheAsync(buffer, nullptr); } @@ -798,8 +797,8 @@ status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const sp& buffer) { - mImageManager->releaseAsync(buffer->getId(), nullptr); +void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { + mImageManager->releaseAsync(bufferId, nullptr); } std::shared_ptr GLESRenderEngine::unbindExternalTextureBufferForTesting( @@ -1103,7 +1102,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, const std::vector& layers, - const std::shared_ptr& buffer, + const sp& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence, base::unique_fd* drawFence) { ATRACE_CALL(); @@ -1126,7 +1125,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, return BAD_VALUE; } - validateOutputBufferUsage(buffer->getBuffer()); + validateOutputBufferUsage(buffer); std::unique_ptr fbo; // Gathering layers that requested blur, we'll need them to decide when to render to an @@ -1143,13 +1142,11 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, if (blurLayersSize == 0) { fbo = std::make_unique(*this, - buffer->getBuffer() - .get() - ->getNativeBuffer(), + buffer.get()->getNativeBuffer(), useFramebufferCache); if (fbo->getStatus() != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); + buffer->handle); checkErrors(); return fbo->getStatus(); } @@ -1160,7 +1157,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, mBlurFilter->setAsDrawTarget(display, blurLayers.front()->backgroundBlurRadius); if (status != NO_ERROR) { ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); + buffer->handle); checkErrors(); return status; } @@ -1197,7 +1194,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, auto status = mBlurFilter->prepare(); if (status != NO_ERROR) { ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); + buffer->handle); checkErrors("Can't render first blur pass"); return status; } @@ -1206,7 +1203,6 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, // Done blurring, time to bind the native FBO and render our blur onto it. fbo = std::make_unique(*this, buffer.get() - ->getBuffer() ->getNativeBuffer(), useFramebufferCache); status = fbo->getStatus(); @@ -1219,7 +1215,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, } if (status != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); + buffer->handle); checkErrors("Can't bind native framebuffer"); return status; } @@ -1227,7 +1223,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, status = mBlurFilter->render(blurLayersSize > 1); if (status != NO_ERROR) { ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); + buffer->handle); checkErrors("Can't render blur filter"); return status; } @@ -1254,7 +1250,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, disableTexture = false; isOpaque = layer->source.buffer.isOpaque; - sp gBuf = layer->source.buffer.buffer->getBuffer(); + sp gBuf = layer->source.buffer.buffer; validateInputBufferUsage(gBuf); bindExternalTextureBuffer(layer->source.buffer.textureName, gBuf, layer->source.buffer.fence); @@ -1278,7 +1274,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, // Do not cache protected EGLImage, protected memory is limited. if (gBuf->getUsage() & GRALLOC_USAGE_PROTECTED) { - unmapExternalTextureBuffer(gBuf); + unbindExternalTextureBuffer(gBuf->getId()); } } diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index e7ed9c01fa..cd7a86bb0e 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -60,14 +60,16 @@ public: void primeCache() override; void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; + void cacheExternalTextureBuffer(const sp& buffer) EXCLUDES(mRenderingMutex); + void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex); + bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; bool useProtectedContext(bool useProtectedContext) override; status_t drawLayers(const DisplaySettings& display, const std::vector& layers, - const std::shared_ptr& buffer, - const bool useFramebufferCache, base::unique_fd&& bufferFence, - base::unique_fd* drawFence) override; + const sp& buffer, const bool useFramebufferCache, + base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; bool cleanupPostRender(CleanupMode mode) override; int getContextPriority() override; bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } @@ -103,9 +105,6 @@ protected: EXCLUDES(mFramebufferImageCacheMutex); size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; - void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) - EXCLUDES(mRenderingMutex); - void unmapExternalTextureBuffer(const sp& buffer) EXCLUDES(mRenderingMutex); private: friend class BindNativeBufferAsFramebuffer; diff --git a/libs/renderengine/include/renderengine/ExternalTexture.h b/libs/renderengine/include/renderengine/ExternalTexture.h deleted file mode 100644 index 07f0833d4a..0000000000 --- a/libs/renderengine/include/renderengine/ExternalTexture.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2021 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 -#include - -namespace android::renderengine { - -class RenderEngine; - -/** - * Manages GPU image resources on behalf of clients using RenderEngine. - * - * Clients of RenderEngine are required to wrap their GraphicBuffer objects as an ExternalTexture, - * which is then mapped into GPU resources required by RenderEngine. When a client no longer needs - * to use the GraphicBuffer as input into RenderEngine::drawLayers, then the client should delete - * their ExternalTexture so that resources may be freed. - */ -class ExternalTexture { -public: - // Usage specifies the rendering intent for the buffer. - enum Usage : uint32_t { - // When a buffer is not READABLE but is WRITEABLE, then GLESRenderEngine will use that as a - // hint to load the buffer into a separate cache - READABLE = 1 << 0, - - // The buffer needs to be mapped as a 2D texture if set, otherwise must be mapped as an - // external texture - WRITEABLE = 1 << 1, - }; - // Creates an ExternalTexture for the provided buffer and RenderEngine instance, with the given - // usage hint of type Usage. - ExternalTexture(const sp& buffer, RenderEngine& renderEngine, uint32_t usage); - - ~ExternalTexture(); - - // Retrieves the buffer that is bound to this texture. - const sp& getBuffer() const { return mBuffer; } - -private: - sp mBuffer; - RenderEngine& mRenderEngine; - DISALLOW_COPY_AND_ASSIGN(ExternalTexture); -}; - -} // namespace android::renderengine diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index c54c5ba047..7661233967 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -16,9 +16,11 @@ #pragma once +#include + #include #include -#include +#include #include #include #include @@ -29,8 +31,6 @@ #include #include -#include - namespace android { namespace renderengine { @@ -39,7 +39,7 @@ struct Buffer { // Buffer containing the image that we will render. // If buffer == nullptr, then the rest of the fields in this struct will be // ignored. - std::shared_ptr buffer = nullptr; + sp buffer = nullptr; // Fence that will fire when the buffer is ready to be bound. sp fence = nullptr; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index c8a0f0a034..8dd98c3ba3 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -17,20 +17,19 @@ #ifndef SF_RENDERENGINE_H_ #define SF_RENDERENGINE_H_ +#include +#include +#include + #include #include #include -#include #include #include #include -#include -#include #include #include -#include - /** * Allows to set RenderEngine backend to GLES (default) or SkiaGL (NOT yet supported). */ @@ -52,7 +51,6 @@ class Region; namespace renderengine { -class ExternalTexture; class Image; class Mesh; class Texture; @@ -106,6 +104,23 @@ public: virtual void genTextures(size_t count, uint32_t* names) = 0; virtual void deleteTextures(size_t count, uint32_t const* names) = 0; + // Caches Image resources for this buffer, but does not bind the buffer to + // a particular texture. + // Note that work is deferred to an additional thread, i.e. this call + // is made asynchronously, but the caller can expect that cache/unbind calls + // are performed in a manner that's conflict serializable, i.e. unbinding + // a buffer should never occur before binding the buffer if the caller + // called {bind, cache}ExternalTextureBuffer before calling unbind. + virtual void cacheExternalTextureBuffer(const sp& buffer) = 0; + // Removes internal resources referenced by the bufferId. This method should be + // invoked when the caller will no longer hold a reference to a GraphicBuffer + // and needs to clean up its resources. + // Note that work is deferred to an additional thread, i.e. this call + // is made asynchronously, but the caller can expect that cache/unbind calls + // are performed in a manner that's conflict serializable, i.e. unbinding + // a buffer should never occur before binding the buffer if the caller + // called {bind, cache}ExternalTextureBuffer before calling unbind. + virtual void unbindExternalTextureBuffer(uint64_t bufferId) = 0; enum class CleanupMode { CLEAN_OUTPUT_RESOURCES, @@ -176,9 +191,8 @@ public: // now, this always returns NO_ERROR. virtual status_t drawLayers(const DisplaySettings& display, const std::vector& layers, - const std::shared_ptr& buffer, - const bool useFramebufferCache, base::unique_fd&& bufferFence, - base::unique_fd* drawFence) = 0; + const sp& buffer, const bool useFramebufferCache, + base::unique_fd&& bufferFence, base::unique_fd* drawFence) = 0; virtual void cleanFramebufferCache() = 0; // Returns the priority this context was actually created with. Note: this may not be // the same as specified at context creation time, due to implementation limits on the @@ -199,31 +213,6 @@ public: static void validateOutputBufferUsage(const sp&); protected: - // Maps GPU resources for this buffer. - // Note that work may be deferred to an additional thread, i.e. this call - // is made asynchronously, but the caller can expect that map/unmap calls - // are performed in a manner that's conflict serializable, i.e. unmapping - // a buffer should never occur before binding the buffer if the caller - // called mapExternalTextureBuffer before calling unmap. - // Note also that if the buffer contains protected content, then mapping those GPU resources may - // be deferred until the buffer is really used for drawing. This is because typical SoCs that - // support protected memory only support a limited amount, so optimisitically mapping protected - // memory may be too burdensome. If a buffer contains protected content and the RenderEngine - // implementation supports protected context, then GPU resources may be mapped into both the - // protected and unprotected contexts. - // If the buffer may ever be written to by RenderEngine, then isRenderable must be true. - virtual void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) = 0; - // Unmaps GPU resources used by this buffer. This method should be - // invoked when the caller will no longer hold a reference to a GraphicBuffer - // and needs to clean up its resources. - // Note that if there are multiple callers holding onto the same buffer, then the buffer's - // resources may be internally ref-counted to guard against use-after-free errors. Note that - // work may be deferred to an additional thread, i.e. this call is expected to be made - // asynchronously, but the caller can expect that map/unmap calls are performed in a manner - // that's conflict serializable, i.e. unmap a buffer should never occur before binding the - // buffer if the caller called mapExternalTextureBuffer before calling unmap. - virtual void unmapExternalTextureBuffer(const sp& buffer) = 0; - friend class ExternalTexture; friend class threaded::RenderEngineThreaded; const RenderEngineType mRenderEngineType; }; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index 27dbd1ecf3..228553d643 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -39,6 +39,8 @@ public: MOCK_METHOD1(dump, void(std::string&)); MOCK_METHOD2(genTextures, void(size_t, uint32_t*)); MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*)); + MOCK_METHOD1(cacheExternalTextureBuffer, void(const sp&)); + MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t)); MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&)); MOCK_CONST_METHOD0(getMaxTextureSize, size_t()); MOCK_CONST_METHOD0(getMaxViewportDims, size_t()); @@ -48,17 +50,12 @@ public: MOCK_METHOD1(cleanupPostRender, bool(CleanupMode mode)); MOCK_METHOD6(drawLayers, status_t(const DisplaySettings&, const std::vector&, - const std::shared_ptr&, const bool, base::unique_fd&&, + const sp&, const bool, base::unique_fd&&, base::unique_fd*)); MOCK_METHOD0(cleanFramebufferCache, void()); MOCK_METHOD0(getContextPriority, int()); MOCK_METHOD0(supportsBackgroundBlur, bool()); MOCK_METHOD1(onPrimaryDisplaySizeChanged, void(ui::Size)); - -protected: - // mock renderengine still needs to implement these, but callers should never need to call them. - void mapExternalTextureBuffer(const sp&, bool) {} - void unmapExternalTextureBuffer(const sp&) {} }; } // namespace mock diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h index 2d61cf854b..bb758780e1 100644 --- a/libs/renderengine/skia/AutoBackendTexture.h +++ b/libs/renderengine/skia/AutoBackendTexture.h @@ -21,9 +21,9 @@ #include #include #include -#include #include "android-base/macros.h" +#include "ui/GraphicTypes.h" namespace android { namespace renderengine { @@ -41,18 +41,13 @@ public: // of shared ownership with Skia objects, so we wrap it here instead. class LocalRef { public: - LocalRef(AutoBackendTexture* texture) { setTexture(texture); } + LocalRef() {} ~LocalRef() { // Destroying the texture is the same as setting it to null setTexture(nullptr); } - AutoBackendTexture* getTexture() const { return mTexture; } - - DISALLOW_COPY_AND_ASSIGN(LocalRef); - - private: // Sets the texture to locally ref-track. void setTexture(AutoBackendTexture* texture) { if (mTexture != nullptr) { @@ -64,6 +59,12 @@ public: mTexture->ref(); } } + + AutoBackendTexture* getTexture() const { return mTexture; } + + DISALLOW_COPY_AND_ASSIGN(LocalRef); + + private: AutoBackendTexture* mTexture = nullptr; }; diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index 1c2b2fc3ca..1db20c0be0 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -46,7 +46,7 @@ constexpr auto kDestDataSpace = ui::Dataspace::SRGB; } // namespace static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - const std::shared_ptr& dstTexture) { + sp dstBuffer) { // Somewhat arbitrary dimensions, but on screen and slightly shorter, based // on actual use. FloatRect rect(0, 0, display.physicalDisplay.width(), display.physicalDisplay.height() - 30); @@ -73,7 +73,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin auto layers = std::vector{&layer}; // The identity matrix will generate the fast shader - renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), + renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, base::unique_fd(), nullptr); // This matrix, which has different scales for x and y, will // generate the slower (more general case) version, which has variants for translucent @@ -86,14 +86,13 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin // clang-format on for (auto translucent : {false, true}) { layer.shadow.casterIsTranslucent = translucent; - renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, base::unique_fd(), nullptr); } } static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - const std::shared_ptr& dstTexture, - const std::shared_ptr& srcTexture) { + sp dstBuffer, sp srcBuffer) { const Rect& displayRect = display.physicalDisplay; FloatRect rect(0, 0, displayRect.width(), displayRect.height()); LayerSettings layer{ @@ -104,7 +103,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting }, .source = PixelSource{.buffer = Buffer{ - .buffer = srcTexture, + .buffer = srcBuffer, .maxMasteringLuminance = 1000.f, .maxContentLuminance = 1000.f, }}, @@ -127,7 +126,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting layer.source.buffer.isOpaque = isOpaque; for (auto alpha : {half(.23999f), half(1.0f)}) { layer.alpha = alpha; - renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, base::unique_fd(), nullptr); } } @@ -136,7 +135,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting } static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - const std::shared_ptr& dstTexture) { + sp dstBuffer) { const Rect& displayRect = display.physicalDisplay; FloatRect rect(0, 0, displayRect.width(), displayRect.height()); LayerSettings layer{ @@ -144,11 +143,11 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting Geometry{ .boundaries = rect, }, + .alpha = 1, .source = PixelSource{ .solidColor = half3(0.1f, 0.2f, 0.3f), }, - .alpha = 1, }; auto layers = std::vector{&layer}; @@ -156,14 +155,14 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting layer.geometry.positionTransform = transform; for (float roundedCornersRadius : {0.0f, 0.05f, 50.f}) { layer.geometry.roundedCornersRadius = roundedCornersRadius; - renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, base::unique_fd(), nullptr); } } } static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - const std::shared_ptr& dstTexture) { + sp dstBuffer) { const Rect& displayRect = display.physicalDisplay; FloatRect rect(0, 0, displayRect.width(), displayRect.height()); LayerSettings layer{ @@ -177,7 +176,7 @@ static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings auto layers = std::vector{&layer}; for (int radius : {9, 60}) { layer.backgroundBlurRadius = radius; - renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, base::unique_fd(), nullptr); } } @@ -215,9 +214,6 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { sp dstBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usage, "primeShaderCache_dst"); - - const auto dstTexture = std::make_shared(dstBuffer, *renderengine, - ExternalTexture::Usage::WRITEABLE); // This buffer will be the source for the call to drawImageLayers. Draw // something to it as a placeholder for what an app draws. We should draw // something, but the details are not important. Make use of the shadow layer drawing step @@ -226,16 +222,11 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usage, "drawImageLayer_src"); - const auto srcTexture = - std::make_shared(srcBuffer, *renderengine, - ExternalTexture::Usage::READABLE | - ExternalTexture::Usage::WRITEABLE); - - drawSolidLayers(renderengine, display, dstTexture); - drawShadowLayers(renderengine, display, srcTexture); - drawBlurLayers(renderengine, display, dstTexture); + drawSolidLayers(renderengine, display, dstBuffer); + drawShadowLayers(renderengine, display, srcBuffer); + drawBlurLayers(renderengine, display, dstBuffer); // The majority of shaders are related to sampling images. - drawImageLayers(renderengine, display, dstTexture, srcTexture); + drawImageLayers(renderengine, display, dstBuffer, srcBuffer); // should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE; @@ -243,12 +234,12 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { sp externalBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usageExternal, "primeShaderCache_external"); - const auto externalTexture = - std::make_shared(externalBuffer, *renderengine, - ExternalTexture::Usage::READABLE); // TODO(b/184665179) doubles number of image shader compilations, but only somewhere // between 6 and 8 will occur in real uses. - drawImageLayers(renderengine, display, dstTexture, externalTexture); + drawImageLayers(renderengine, display, dstBuffer, externalBuffer); + renderengine->unbindExternalTextureBuffer(externalBuffer->getId()); + + renderengine->unbindExternalTextureBuffer(srcBuffer->getId()); const nsecs_t timeAfter = systemTime(); const float compileTimeMs = static_cast(timeAfter - timeBefore) / 1.0E6; diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index e781584a9b..3b2c7e5f66 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -329,6 +329,8 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL } SkiaGLRenderEngine::~SkiaGLRenderEngine() { + cleanFramebufferCache(); + std::lock_guard lock(mRenderingMutex); if (mBlurFilter) { delete mBlurFilter; @@ -482,8 +484,7 @@ static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destin sourceTransfer != destTransfer; } -void SkiaGLRenderEngine::mapExternalTextureBuffer(const sp& buffer, - bool isRenderable) { +void SkiaGLRenderEngine::cacheExternalTextureBuffer(const sp& buffer) { // Only run this if RE is running on its own thread. This way the access to GL // operations is guaranteed to be happening on the same thread. if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED) { @@ -504,41 +505,25 @@ void SkiaGLRenderEngine::mapExternalTextureBuffer(const sp& buffe auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache; std::lock_guard lock(mRenderingMutex); - mGraphicBufferExternalRefs[buffer->getId()]++; - - if (const auto& iter = cache.find(buffer->getId()); iter == cache.end()) { + auto iter = cache.find(buffer->getId()); + if (iter != cache.end()) { + ALOGV("Texture already exists in cache."); + } else { std::shared_ptr imageTextureRef = - std::make_shared( - new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), - isRenderable)); + std::make_shared(); + imageTextureRef->setTexture( + new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), false)); cache.insert({buffer->getId(), imageTextureRef}); } // restore the original state of the protected context if necessary useProtectedContext(protectedContextState); } -void SkiaGLRenderEngine::unmapExternalTextureBuffer(const sp& buffer) { +void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { ATRACE_CALL(); std::lock_guard lock(mRenderingMutex); - if (const auto& iter = mGraphicBufferExternalRefs.find(buffer->getId()); - iter != mGraphicBufferExternalRefs.end()) { - if (iter->second == 0) { - ALOGW("Attempted to unmap GraphicBuffer from RenderEngine texture, but the " - "ref count was already zero!", - buffer->getId()); - mGraphicBufferExternalRefs.erase(buffer->getId()); - return; - } - - iter->second--; - - if (iter->second == 0) { - mTextureCache.erase(buffer->getId()); - mProtectedTextureCache.erase(buffer->getId()); - mGraphicBufferExternalRefs.erase(buffer->getId()); - } - } + mTextureCache.erase(bufferId); + mProtectedTextureCache.erase(bufferId); } sk_sp SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp shader, @@ -636,8 +621,8 @@ private: status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, const std::vector& layers, - const std::shared_ptr& buffer, - const bool /*useFramebufferCache*/, + const sp& buffer, + const bool useFramebufferCache, base::unique_fd&& bufferFence, base::unique_fd* drawFence) { ATRACE_NAME("SkiaGL::drawLayers"); @@ -660,18 +645,32 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, return BAD_VALUE; } - validateOutputBufferUsage(buffer->getBuffer()); + validateOutputBufferUsage(buffer); auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext; auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache; + AHardwareBuffer_Desc bufferDesc; + AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc); + + std::shared_ptr surfaceTextureRef = nullptr; + if (useFramebufferCache) { + auto iter = cache.find(buffer->getId()); + if (iter != cache.end()) { + ALOGV("Cache hit!"); + ATRACE_NAME("Cache hit"); + surfaceTextureRef = iter->second; + } + } - std::shared_ptr surfaceTextureRef; - if (const auto& it = cache.find(buffer->getBuffer()->getId()); it != cache.end()) { - surfaceTextureRef = it->second; - } else { - surfaceTextureRef = std::make_shared( - new AutoBackendTexture(grContext.get(), buffer->getBuffer()->toAHardwareBuffer(), - true)); + if (surfaceTextureRef == nullptr || surfaceTextureRef->getTexture() == nullptr) { + ATRACE_NAME("Cache miss"); + surfaceTextureRef = std::make_shared(); + surfaceTextureRef->setTexture( + new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), true)); + if (useFramebufferCache) { + ALOGD("Adding to cache"); + cache.insert({buffer->getId(), surfaceTextureRef}); + } } const ui::Dataspace dstDataspace = @@ -877,22 +876,18 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, SkPaint paint; if (layer->source.buffer.buffer) { ATRACE_NAME("DrawImage"); - validateInputBufferUsage(layer->source.buffer.buffer->getBuffer()); + validateInputBufferUsage(layer->source.buffer.buffer); const auto& item = layer->source.buffer; std::shared_ptr imageTextureRef = nullptr; - - if (const auto& iter = cache.find(item.buffer->getBuffer()->getId()); - iter != cache.end()) { + auto iter = cache.find(item.buffer->getId()); + if (iter != cache.end()) { imageTextureRef = iter->second; } else { - // If we didn't find the image in the cache, then create a local ref but don't cache - // it. If we're using skia, we're guaranteed to run on a dedicated GPU thread so if - // we didn't find anything in the cache then we intentionally did not cache this - // buffer's resources. - imageTextureRef = std::make_shared( - new AutoBackendTexture(grContext.get(), - item.buffer->getBuffer()->toAHardwareBuffer(), - false)); + imageTextureRef = std::make_shared(); + imageTextureRef->setTexture(new AutoBackendTexture(grContext.get(), + item.buffer->toAHardwareBuffer(), + false)); + cache.insert({item.buffer->getId(), imageTextureRef}); } sk_sp image = @@ -1205,6 +1200,15 @@ EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay dis return eglCreatePbufferSurface(display, placeholderConfig, attributes.data()); } +void SkiaGLRenderEngine::cleanFramebufferCache() { + // TODO(b/180767535) Remove this method and use b/180767535 instead, which would allow + // SF to control texture lifecycle more tightly rather than through custom hooks into RE. + std::lock_guard lock(mRenderingMutex); + mRuntimeEffects.clear(); + mProtectedTextureCache.clear(); + mTextureCache.clear(); +} + int SkiaGLRenderEngine::getContextPriority() { int value; eglQueryContext(mEGLDisplay, mEGLContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &value); @@ -1277,12 +1281,6 @@ void SkiaGLRenderEngine::dump(std::string& result) { StringAppendF(&result, "Skia's Wrapped Objects:\n"); gpuReporter.logOutput(result, true); - StringAppendF(&result, "RenderEngine tracked buffers: %zu\n", - mGraphicBufferExternalRefs.size()); - StringAppendF(&result, "Dumping buffer ids...\n"); - for (const auto& [id, refCounts] : mGraphicBufferExternalRefs) { - StringAppendF(&result, "- 0x%" PRIx64 " - %d refs \n", id, refCounts); - } StringAppendF(&result, "RenderEngine AHB/BackendTexture cache size: %zu\n", mTextureCache.size()); StringAppendF(&result, "Dumping buffer ids...\n"); diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index e71c560a1f..8e77c16b40 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -53,12 +52,13 @@ public: ~SkiaGLRenderEngine() override EXCLUDES(mRenderingMutex); void primeCache() override; + void cacheExternalTextureBuffer(const sp& buffer) override; + void unbindExternalTextureBuffer(uint64_t bufferId) override; status_t drawLayers(const DisplaySettings& display, const std::vector& layers, - const std::shared_ptr& buffer, - const bool useFramebufferCache, base::unique_fd&& bufferFence, - base::unique_fd* drawFence) override; - void cleanFramebufferCache() override {} + const sp& buffer, const bool useFramebufferCache, + base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; + void cleanFramebufferCache() override; int getContextPriority() override; bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; @@ -72,8 +72,6 @@ protected: void dump(std::string& result) override; size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; - void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) override; - void unmapExternalTextureBuffer(const sp& buffer) override; private: static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); @@ -116,9 +114,7 @@ private: const PixelFormat mDefaultPixelFormat; const bool mUseColorManagement; - // Number of external holders of ExternalTexture references, per GraphicBuffer ID. - std::unordered_map mGraphicBufferExternalRefs GUARDED_BY(mRenderingMutex); - // Cache of GL textures that we'll store per GraphicBuffer ID, sliced by GPU context. + // Cache of GL textures that we'll store per GraphicBuffer ID std::unordered_map> mTextureCache GUARDED_BY(mRenderingMutex); std::unordered_map> diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 308c5ffa9f..51ef088a25 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -42,12 +42,15 @@ public: virtual void primeCache() override{}; virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override{}; virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{}; + virtual void cacheExternalTextureBuffer(const sp& /*buffer*/){}; + virtual void unbindExternalTextureBuffer(uint64_t /*bufferId*/){}; + virtual bool isProtected() const override { return false; } // mInProtectedContext; } virtual bool supportsProtectedContent() const override { return false; }; virtual bool useProtectedContext(bool /*useProtectedContext*/) override { return false; }; virtual status_t drawLayers(const DisplaySettings& /*display*/, const std::vector& /*layers*/, - const std::shared_ptr& /*buffer*/, + const sp& /*buffer*/, const bool /*useFramebufferCache*/, base::unique_fd&& /*bufferFence*/, base::unique_fd* /*drawFence*/) override { @@ -57,11 +60,6 @@ public: virtual int getContextPriority() override { return 0; } virtual void assertShadersCompiled(int numShaders) {} virtual int reportShadersCompiled() { return 0; } - -protected: - virtual void mapExternalTextureBuffer(const sp& /*buffer*/, - bool /*isRenderable*/) override; - virtual void unmapExternalTextureBuffer(const sp& /*buffer*/) override; }; } // namespace skia diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index d63c88bc02..7846156383 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -161,42 +160,27 @@ public: class RenderEngineTest : public ::testing::TestWithParam> { public: - std::shared_ptr allocateDefaultBuffer() { - return std::make_shared< - renderengine:: - ExternalTexture>(new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, - DEFAULT_DISPLAY_HEIGHT, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_SW_READ_OFTEN | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | - GRALLOC_USAGE_HW_TEXTURE, - "output"), - *mRE, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + static sp allocateDefaultBuffer() { + return new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, + "output"); } // Allocates a 1x1 buffer to fill with a solid color - std::shared_ptr allocateSourceBuffer(uint32_t width, - uint32_t height) { - return std::make_shared< - renderengine:: - ExternalTexture>(new GraphicBuffer(width, height, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_SW_READ_OFTEN | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_TEXTURE, - "input"), - *mRE, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + static sp allocateSourceBuffer(uint32_t width, uint32_t height) { + return new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_TEXTURE, + "input"); } RenderEngineTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + mBuffer = allocateDefaultBuffer(); } ~RenderEngineTest() { @@ -227,21 +211,20 @@ public: } uint8_t* pixels; - mBuffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + mBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); file << "P6\n"; - file << mBuffer->getBuffer()->getWidth() << "\n"; - file << mBuffer->getBuffer()->getHeight() << "\n"; + file << mBuffer->getWidth() << "\n"; + file << mBuffer->getHeight() << "\n"; file << 255 << "\n"; - std::vector outBuffer(mBuffer->getBuffer()->getWidth() * - mBuffer->getBuffer()->getHeight() * 3); + std::vector outBuffer(mBuffer->getWidth() * mBuffer->getHeight() * 3); auto outPtr = reinterpret_cast(outBuffer.data()); - for (int32_t j = 0; j < mBuffer->getBuffer()->getHeight(); j++) { - const uint8_t* src = pixels + (mBuffer->getBuffer()->getStride() * j) * 4; - for (int32_t i = 0; i < mBuffer->getBuffer()->getWidth(); i++) { + for (int32_t j = 0; j < mBuffer->getHeight(); j++) { + const uint8_t* src = pixels + (mBuffer->getStride() * j) * 4; + for (int32_t i = 0; i < mBuffer->getWidth(); i++) { // Only copy R, G and B components outPtr[0] = src[0]; outPtr[1] = src[1]; @@ -252,7 +235,7 @@ public: } } file.write(reinterpret_cast(outBuffer.data()), outBuffer.size()); - mBuffer->getBuffer()->unlock(); + mBuffer->unlock(); } void expectBufferColor(const Region& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { @@ -279,13 +262,13 @@ public: void expectBufferColor(const Rect& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a, std::function colorCompare) { uint8_t* pixels; - mBuffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + mBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); int32_t maxFails = 10; int32_t fails = 0; for (int32_t j = 0; j < region.getHeight(); j++) { - const uint8_t* src = pixels + - (mBuffer->getBuffer()->getStride() * (region.top + j) + region.left) * 4; + const uint8_t* src = + pixels + (mBuffer->getStride() * (region.top + j) + region.left) * 4; for (int32_t i = 0; i < region.getWidth(); i++) { const uint8_t expected[4] = {r, g, b, a}; bool equal = colorCompare(src, expected); @@ -306,7 +289,7 @@ public: break; } } - mBuffer->getBuffer()->unlock(); + mBuffer->unlock(); } void expectAlpha(const Rect& rect, uint8_t a) { @@ -404,6 +387,7 @@ public: base::unique_fd fence; status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fence); + mCurrentBuffer = mBuffer; int fd = fence.release(); if (fd >= 0) { @@ -413,7 +397,7 @@ public: ASSERT_EQ(NO_ERROR, status); if (layers.size() > 0 && mGLESRE != nullptr) { - ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId())); + ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId())); } } @@ -519,11 +503,17 @@ public: void initializeRenderEngine(); std::unique_ptr mRE; - std::shared_ptr mBuffer; // GLESRenderEngine for testing GLES-specific behavior. // Owened by mRE, but this is downcasted. renderengine::gl::GLESRenderEngine* mGLESRE = nullptr; + // Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to + // be freed *after* RenderEngine is destroyed, so that the EGL image is + // destroyed first. + sp mCurrentBuffer; + + sp mBuffer; + std::vector mTexNames; }; @@ -540,7 +530,6 @@ void RenderEngineTest::initializeRenderEngine() { } else { mRE = renderEngineFactory->createRenderEngine(); } - mBuffer = allocateDefaultBuffer(); } struct ColorSourceVariant { @@ -577,18 +566,18 @@ template struct BufferSourceVariant { static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b, RenderEngineTest* fixture) { - const auto buf = fixture->allocateSourceBuffer(1, 1); + sp buf = RenderEngineTest::allocateSourceBuffer(1, 1); uint32_t texName; fixture->mRE->genTextures(1, &texName); fixture->mTexNames.push_back(texName); uint8_t* pixels; - buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); - for (int32_t j = 0; j < buf->getBuffer()->getHeight(); j++) { - uint8_t* iter = pixels + (buf->getBuffer()->getStride() * j) * 4; - for (int32_t i = 0; i < buf->getBuffer()->getWidth(); i++) { + for (int32_t j = 0; j < buf->getHeight(); j++) { + uint8_t* iter = pixels + (buf->getStride() * j) * 4; + for (int32_t i = 0; i < buf->getWidth(); i++) { iter[0] = uint8_t(r * 255); iter[1] = uint8_t(g * 255); iter[2] = uint8_t(b * 255); @@ -597,7 +586,7 @@ struct BufferSourceVariant { } } - buf->getBuffer()->unlock(); + buf->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1023,14 +1012,14 @@ void RenderEngineTest::fillRedBufferTextureTransform() { layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; // Here will allocate a checker board texture, but transform texture // coordinates so that only the upper left is applied. - const auto buf = allocateSourceBuffer(2, 2); + sp buf = allocateSourceBuffer(2, 2); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; - buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); // Red top left, Green top right, Blue bottom left, Black bottom right pixels[0] = 255; pixels[1] = 0; @@ -1044,7 +1033,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() { pixels[9] = 0; pixels[10] = 255; pixels[11] = 255; - buf->getBuffer()->unlock(); + buf->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1072,19 +1061,19 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() { std::vector layers; renderengine::LayerSettings layer; - const auto buf = allocateSourceBuffer(1, 1); + sp buf = allocateSourceBuffer(1, 1); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; - buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); pixels[0] = 255; pixels[1] = 0; pixels[2] = 0; pixels[3] = 255; - buf->getBuffer()->unlock(); + buf->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1111,19 +1100,19 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() { std::vector layers; renderengine::LayerSettings layer; - const auto buf = allocateSourceBuffer(1, 1); + sp buf = allocateSourceBuffer(1, 1); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; - buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); pixels[0] = 255; pixels[1] = 0; pixels[2] = 0; pixels[3] = 255; - buf->getBuffer()->unlock(); + buf->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1244,7 +1233,8 @@ TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) { } TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) { - initializeRenderEngine(); + const auto& renderEngineFactory = GetParam(); + mRE = renderEngineFactory->createRenderEngine(); renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1305,6 +1295,7 @@ TEST_P(RenderEngineTest, drawLayers_nullOutputFence) { layers.push_back(&layer); status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), nullptr); + mCurrentBuffer = mBuffer; ASSERT_EQ(NO_ERROR, status); expectBufferColor(fullscreenRect(), 255, 0, 0, 255); } @@ -1332,8 +1323,9 @@ TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) { layers.push_back(&layer); status_t status = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd(), nullptr); + mCurrentBuffer = mBuffer; ASSERT_EQ(NO_ERROR, status); - ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId())); + ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId())); expectBufferColor(fullscreenRect(), 255, 0, 0, 255); } @@ -1582,6 +1574,98 @@ TEST_P(RenderEngineTest, drawLayers_clearRegion) { clearRegion(); } +TEST_P(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) { + const auto& renderEngineFactory = GetParam(); + + if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { + // GLES-specific test + return; + } + + initializeRenderEngine(); + + renderengine::DisplaySettings settings; + settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; + settings.physicalDisplay = fullscreenRect(); + settings.clip = fullscreenRect(); + + std::vector layers; + + renderengine::LayerSettings layer; + layer.geometry.boundaries = fullscreenRect().toFloatRect(); + BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); + + layers.push_back(&layer); + invokeDraw(settings, layers); + uint64_t bufferId = layer.source.buffer.buffer->getId(); + EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId)); + std::shared_ptr barrier = + mGLESRE->unbindExternalTextureBufferForTesting(bufferId); + std::lock_guard lock(barrier->mutex); + ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), + [&]() REQUIRES(barrier->mutex) { + return barrier->isOpen; + })); + EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId)); + EXPECT_EQ(NO_ERROR, barrier->result); +} + +TEST_P(RenderEngineTest, cacheExternalBuffer_withNullBuffer) { + const auto& renderEngineFactory = GetParam(); + + if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { + // GLES-specific test + return; + } + + initializeRenderEngine(); + + std::shared_ptr barrier = + mGLESRE->cacheExternalTextureBufferForTesting(nullptr); + std::lock_guard lock(barrier->mutex); + ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), + [&]() REQUIRES(barrier->mutex) { + return barrier->isOpen; + })); + EXPECT_TRUE(barrier->isOpen); + EXPECT_EQ(BAD_VALUE, barrier->result); +} + +TEST_P(RenderEngineTest, cacheExternalBuffer_cachesImages) { + const auto& renderEngineFactory = GetParam(); + + if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { + // GLES-specific test + return; + } + + initializeRenderEngine(); + + sp buf = allocateSourceBuffer(1, 1); + uint64_t bufferId = buf->getId(); + std::shared_ptr barrier = + mGLESRE->cacheExternalTextureBufferForTesting(buf); + { + std::lock_guard lock(barrier->mutex); + ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), + [&]() REQUIRES(barrier->mutex) { + return barrier->isOpen; + })); + EXPECT_EQ(NO_ERROR, barrier->result); + } + EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId)); + barrier = mGLESRE->unbindExternalTextureBufferForTesting(bufferId); + { + std::lock_guard lock(barrier->mutex); + ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), + [&]() REQUIRES(barrier->mutex) { + return barrier->isOpen; + })); + EXPECT_EQ(NO_ERROR, barrier->result); + } + EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId)); +} + TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) { initializeRenderEngine(); @@ -1774,7 +1858,7 @@ TEST_P(RenderEngineTest, cleanupPostRender_whenCleaningAll_replacesTextureMemory sync_wait(fd, -1); } - uint64_t bufferId = layer.source.buffer.buffer->getBuffer()->getId(); + uint64_t bufferId = layer.source.buffer.buffer->getId(); uint32_t texName = layer.source.buffer.textureName; EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId)); EXPECT_EQ(bufferId, mGLESRE->getBufferIdForTextureNameForTesting(texName)); @@ -1882,16 +1966,16 @@ TEST_P(RenderEngineTest, testDisableBlendingBuffer) { // The next layer will overwrite redLayer with a GraphicBuffer that is green // applied with a translucent alpha. - const auto buf = allocateSourceBuffer(1, 1); + auto buf = allocateSourceBuffer(1, 1); { uint8_t* pixels; - buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); pixels[0] = 0; pixels[1] = 255; pixels[2] = 0; pixels[3] = 255; - buf->getBuffer()->unlock(); + buf->unlock(); } const renderengine::LayerSettings greenLayer{ diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index e3917cce09..b093e88d4f 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -162,18 +162,15 @@ TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsTrue) { TEST_F(RenderEngineThreadedTest, drawLayers) { renderengine::DisplaySettings settings; std::vector layers; - std::shared_ptr buffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(), *mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + sp buffer = new GraphicBuffer(); base::unique_fd bufferFence; base::unique_fd drawFence; EXPECT_CALL(*mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings&, const std::vector&, - const std::shared_ptr&, const bool, - base::unique_fd&&, base::unique_fd*) -> status_t { return NO_ERROR; }); + const sp&, const bool, base::unique_fd&&, + base::unique_fd*) -> status_t { return NO_ERROR; }); status_t result = mThreadedRE->drawLayers(settings, layers, buffer, false, std::move(bufferFence), &drawFence); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index c9f6296b49..194c7da1c7 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -157,28 +157,27 @@ void RenderEngineThreaded::deleteTextures(size_t count, uint32_t const* names) { resultFuture.wait(); } -void RenderEngineThreaded::mapExternalTextureBuffer(const sp& buffer, - bool isRenderable) { +void RenderEngineThreaded::cacheExternalTextureBuffer(const sp& buffer) { // This function is designed so it can run asynchronously, so we do not need to wait // for the futures. { std::lock_guard lock(mThreadMutex); mFunctionCalls.push([=](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::mapExternalTextureBuffer"); - instance.mapExternalTextureBuffer(buffer, isRenderable); + ATRACE_NAME("REThreaded::cacheExternalTextureBuffer"); + instance.cacheExternalTextureBuffer(buffer); }); } mCondition.notify_one(); } -void RenderEngineThreaded::unmapExternalTextureBuffer(const sp& buffer) { +void RenderEngineThreaded::unbindExternalTextureBuffer(uint64_t bufferId) { // This function is designed so it can run asynchronously, so we do not need to wait // for the futures. { std::lock_guard lock(mThreadMutex); mFunctionCalls.push([=](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::unmapExternalTextureBuffer"); - instance.unmapExternalTextureBuffer(buffer); + ATRACE_NAME("REThreaded::unbindExternalTextureBuffer"); + instance.unbindExternalTextureBuffer(bufferId); }); } mCondition.notify_one(); @@ -240,7 +239,7 @@ bool RenderEngineThreaded::cleanupPostRender(CleanupMode mode) { status_t RenderEngineThreaded::drawLayers(const DisplaySettings& display, const std::vector& layers, - const std::shared_ptr& buffer, + const sp& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence, base::unique_fd* drawFence) { diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index eb6098ed8d..61ae9b8cf8 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -48,6 +48,8 @@ public: void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; + void cacheExternalTextureBuffer(const sp& buffer) override; + void unbindExternalTextureBuffer(uint64_t bufferId) override; size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; @@ -58,19 +60,14 @@ public: status_t drawLayers(const DisplaySettings& display, const std::vector& layers, - const std::shared_ptr& buffer, - const bool useFramebufferCache, base::unique_fd&& bufferFence, - base::unique_fd* drawFence) override; + const sp& buffer, const bool useFramebufferCache, + base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; void cleanFramebufferCache() override; int getContextPriority() override; bool supportsBackgroundBlur() override; void onPrimaryDisplaySizeChanged(ui::Size size) override; -protected: - void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) override; - void unmapExternalTextureBuffer(const sp& buffer) override; - private: void threadMain(CreateInstanceFactory factory); void waitUntilInitialized() const; diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 13ac7c3563..be9bce0795 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -188,7 +188,7 @@ std::optional BufferLayer::prepareCli const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || (isSecure() && !targetSettings.isSecure); const bool bufferCanBeUsedAsHwTexture = - mBufferInfo.mBuffer->getBuffer()->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; + mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; compositionengine::LayerFE::LayerSettings& layer = *result; if (blackOutLayer || !bufferCanBeUsedAsHwTexture) { ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable", @@ -213,7 +213,7 @@ std::optional BufferLayer::prepareCli ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel : defaultMaxContentLuminance; layer.frameNumber = mCurrentFrameNumber; - layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer()->getId() : 0; + layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0; const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering(); @@ -314,7 +314,7 @@ void BufferLayer::preparePerFrameCompositionState() { : Hwc2::IComposerClient::Composition::DEVICE; } - compositionState->buffer = mBufferInfo.mBuffer->getBuffer(); + compositionState->buffer = mBufferInfo.mBuffer; compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mBufferInfo.mBufferSlot; @@ -442,7 +442,7 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, void BufferLayer::gatherBufferInfo() { mBufferInfo.mPixelFormat = - !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getBuffer()->format; + !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->format; mBufferInfo.mFrameLatencyNeeded = true; } @@ -544,10 +544,10 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, } if (oldBufferInfo.mBuffer != nullptr) { - uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); - if (bufWidth != uint32_t(oldBufferInfo.mBuffer->getBuffer()->width) || - bufHeight != uint32_t(oldBufferInfo.mBuffer->getBuffer()->height)) { + uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); + if (bufWidth != uint32_t(oldBufferInfo.mBuffer->width) || + bufHeight != uint32_t(oldBufferInfo.mBuffer->height)) { recomputeVisibleRegions = true; } } @@ -612,8 +612,8 @@ uint32_t BufferLayer::getEffectiveScalingMode() const { } bool BufferLayer::isProtected() const { - return (mBufferInfo.mBuffer != nullptr) && - (mBufferInfo.mBuffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED); + const sp& buffer(mBufferInfo.mBuffer); + return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED); } // h/w composer set-up @@ -727,8 +727,8 @@ Rect BufferLayer::getBufferSize(const State& s) const { return Rect::INVALID_RECT; } - uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); + uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { @@ -759,8 +759,8 @@ FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const return parentBounds; } - uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); + uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { @@ -802,7 +802,7 @@ Rect BufferLayer::getBufferCrop() const { return mBufferInfo.mCrop; } else if (mBufferInfo.mBuffer != nullptr) { // otherwise we use the whole buffer - return mBufferInfo.mBuffer->getBuffer()->getBounds(); + return mBufferInfo.mBuffer->getBounds(); } else { // if we don't have a buffer yet, we use an empty/invalid crop return Rect(); @@ -847,14 +847,12 @@ ui::Dataspace BufferLayer::translateDataspace(ui::Dataspace dataspace) { } sp BufferLayer::getBuffer() const { - return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr; + return mBufferInfo.mBuffer; } void BufferLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) { - GLConsumer::computeTransformMatrix(outMatrix, - mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() - : nullptr, - mBufferInfo.mCrop, mBufferInfo.mTransform, filteringEnabled); + GLConsumer::computeTransformMatrix(outMatrix, mBufferInfo.mBuffer, mBufferInfo.mCrop, + mBufferInfo.mTransform, filteringEnabled); } void BufferLayer::setInitialValuesForClone(const sp& clonedFrom) { diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 855324710e..b8d3f12322 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -134,7 +134,7 @@ protected: PixelFormat mPixelFormat{PIXEL_FORMAT_NONE}; bool mTransformToDisplayInverse{false}; - std::shared_ptr mBuffer; + sp mBuffer; int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT}; bool mFrameLatencyNeeded{false}; diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 96b22478ab..69d2d11a4d 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -166,7 +167,7 @@ void BufferLayerConsumer::setReleaseFence(const sp& fence) { } auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer - : mCurrentTextureBuffer->getBuffer(); + : mCurrentTextureBuffer->graphicBuffer(); auto err = addReleaseFence(slot, buffer, fence); if (err != OK) { BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); @@ -205,11 +206,9 @@ status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t pres // before, so we need to clean up old references. if (item->mGraphicBuffer != nullptr) { std::lock_guard lock(mImagesMutex); - if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->getBuffer() == nullptr || - mImages[item->mSlot]->getBuffer()->getId() != item->mGraphicBuffer->getId()) { - mImages[item->mSlot] = std::make_shared< - renderengine::ExternalTexture>(item->mGraphicBuffer, mRE, - renderengine::ExternalTexture::Usage::READABLE); + if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->graphicBuffer() == nullptr || + mImages[item->mSlot]->graphicBuffer()->getId() != item->mGraphicBuffer->getId()) { + mImages[item->mSlot] = std::make_shared(item->mGraphicBuffer, mRE); } } @@ -223,8 +222,8 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, int slot = item.mSlot; BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, - (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->getBuffer() != nullptr) - ? mCurrentTextureBuffer->getBuffer()->handle + (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->graphicBuffer() != nullptr) + ? mCurrentTextureBuffer->graphicBuffer()->handle : 0, slot, mSlots[slot].mGraphicBuffer->handle); @@ -232,7 +231,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, // releaseBufferLocked() if we're in shared buffer mode and both buffers are // the same. - std::shared_ptr nextTextureBuffer; + std::shared_ptr nextTextureBuffer; { std::lock_guard lock(mImagesMutex); nextTextureBuffer = mImages[slot]; @@ -242,7 +241,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (pendingRelease == nullptr) { status_t status = - releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->getBuffer()); + releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->graphicBuffer()); if (status < NO_ERROR) { BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), status); @@ -251,7 +250,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, } } else { pendingRelease->currentTexture = mCurrentTexture; - pendingRelease->graphicBuffer = mCurrentTextureBuffer->getBuffer(); + pendingRelease->graphicBuffer = mCurrentTextureBuffer->graphicBuffer(); pendingRelease->isPending = true; } } @@ -302,14 +301,14 @@ void BufferLayerConsumer::setFilteringEnabled(bool enabled) { void BufferLayerConsumer::computeCurrentTransformMatrixLocked() { BLC_LOGV("computeCurrentTransformMatrixLocked"); - if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->getBuffer() == nullptr) { + if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->graphicBuffer() == nullptr) { BLC_LOGD("computeCurrentTransformMatrixLocked: " "mCurrentTextureBuffer is nullptr"); } GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, mCurrentTextureBuffer == nullptr ? nullptr - : mCurrentTextureBuffer->getBuffer(), + : mCurrentTextureBuffer->graphicBuffer(), getCurrentCropLocked(), mCurrentTransform, mFilteringEnabled); } @@ -361,8 +360,7 @@ int BufferLayerConsumer::getCurrentApi() const { return mCurrentApi; } -std::shared_ptr BufferLayerConsumer::getCurrentBuffer( - int* outSlot, sp* outFence) const { +sp BufferLayerConsumer::getCurrentBuffer(int* outSlot, sp* outFence) const { Mutex::Autolock lock(mMutex); if (outSlot != nullptr) { @@ -373,7 +371,7 @@ std::shared_ptr BufferLayerConsumer::getCurrentBu *outFence = mCurrentFence; } - return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer; + return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer->graphicBuffer(); } Rect BufferLayerConsumer::getCurrentCrop() const { @@ -458,12 +456,10 @@ void BufferLayerConsumer::onSidebandStreamChanged() { void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) { if (item.mGraphicBuffer != nullptr && item.mSlot != BufferQueue::INVALID_BUFFER_SLOT) { std::lock_guard lock(mImagesMutex); - const std::shared_ptr& oldImage = mImages[item.mSlot]; - if (oldImage == nullptr || oldImage->getBuffer() == nullptr || - oldImage->getBuffer()->getId() != item.mGraphicBuffer->getId()) { - mImages[item.mSlot] = std::make_shared< - renderengine::ExternalTexture>(item.mGraphicBuffer, mRE, - renderengine::ExternalTexture::Usage::READABLE); + const std::shared_ptr& oldImage = mImages[item.mSlot]; + if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr || + oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) { + mImages[item.mSlot] = std::make_shared(item.mGraphicBuffer, mRE); } } } @@ -503,6 +499,22 @@ void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const ConsumerBase::dumpLocked(result, prefix); } + +BufferLayerConsumer::Image::Image(const sp& graphicBuffer, + renderengine::RenderEngine& engine) + : mGraphicBuffer(graphicBuffer), mRE(engine) { + if (graphicBuffer != nullptr && (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED)) { + return; + } + mRE.cacheExternalTextureBuffer(mGraphicBuffer); +} + +BufferLayerConsumer::Image::~Image() { + if (mGraphicBuffer != nullptr) { + ALOGV("Destroying buffer: %" PRId64, mGraphicBuffer->getId()); + mRE.unbindExternalTextureBuffer(mGraphicBuffer->getId()); + } +} }; // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index 9ed80b46bd..dd39214aff 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -21,11 +21,12 @@ #include #include #include -#include + #include #include #include #include + #include #include #include @@ -38,6 +39,7 @@ class String8; namespace renderengine { class RenderEngine; +class Image; } // namespace renderengine /* @@ -151,8 +153,7 @@ public: // When outSlot is not nullptr, the current buffer slot index is also // returned. Simiarly, when outFence is not nullptr, the current output // fence is returned. - std::shared_ptr getCurrentBuffer( - int* outSlot = nullptr, sp* outFence = nullptr) const; + sp getCurrentBuffer(int* outSlot = nullptr, sp* outFence = nullptr) const; // getCurrentCrop returns the cropping rectangle of the current buffer. Rect getCurrentCrop() const; @@ -257,7 +258,7 @@ private: // mCurrentTextureBuffer is the buffer containing the current texture. It's // possible that this buffer is not associated with any buffer slot, so we // must track it separately in order to support the getCurrentBuffer method. - std::shared_ptr mCurrentTextureBuffer; + std::shared_ptr mCurrentTextureBuffer; // mCurrentCrop is the crop rectangle that applies to the current texture. // It gets set each time updateTexImage is called. @@ -336,8 +337,7 @@ private: int mCurrentTexture; // Shadow buffer cache for cleaning up renderengine references. - std::shared_ptr - mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex); + std::shared_ptr mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex); // Separate mutex guarding the shadow buffer cache. // mImagesMutex can be manipulated with binder threads (e.g. onBuffersAllocated) diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index c533969a5c..ed826a0100 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -71,8 +71,14 @@ BufferStateLayer::~BufferStateLayer() { // original layer and the clone should be removed at the same time so there shouldn't be any // issue with the clone layer trying to use the texture. if (mBufferInfo.mBuffer != nullptr && !isClone()) { - callReleaseBufferCallback(mDrawingState.releaseBufferListener, - mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFence); + // Ensure that mBuffer is uncached from RenderEngine here, as + // RenderEngine may have been using the buffer as an external texture + // after the client uncached the buffer. + auto& engine(mFlinger->getRenderEngine()); + const uint64_t bufferId = mBufferInfo.mBuffer->getId(); + engine.unbindExternalTextureBuffer(bufferId); + callReleaseBufferCallback(mDrawingState.releaseBufferListener, mBufferInfo.mBuffer, + mBufferInfo.mFence); } } @@ -357,9 +363,8 @@ bool BufferStateLayer::addFrameEvent(const sp& acquireFence, nsecs_t post return true; } -bool BufferStateLayer::setBuffer(const std::shared_ptr& buffer, - const sp& acquireFence, nsecs_t postTime, - nsecs_t desiredPresentTime, bool isAutoTimestamp, +bool BufferStateLayer::setBuffer(const sp& buffer, const sp& acquireFence, + nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, std::optional dequeueTime, const FrameTimelineInfo& info, const sp& releaseBufferListener) { @@ -367,14 +372,12 @@ bool BufferStateLayer::setBuffer(const std::shared_ptrgetBuffer() != mDrawingState.buffer->getBuffer()) { + if (mCurrentState.buffer != mDrawingState.buffer) { // If mCurrentState has a buffer, and we are about to update again // before swapping to drawing state, then the first buffer will be // dropped and we should decrement the pending buffer count and // call any release buffer callbacks if set. - callReleaseBufferCallback(mCurrentState.releaseBufferListener, - mCurrentState.buffer->getBuffer(), + callReleaseBufferCallback(mCurrentState.releaseBufferListener, mCurrentState.buffer, mCurrentState.acquireFence); decrementPendingBufferCount(); if (mCurrentState.bufferSurfaceFrameTX != nullptr) { @@ -412,8 +415,8 @@ bool BufferStateLayer::setBuffer(const std::shared_ptrgetBuffer()->getId(); + if (dequeueTime && *dequeueTime != 0) { + const uint64_t bufferId = buffer->getId(); mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str()); mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime, FrameTracer::FrameEvent::DEQUEUE); @@ -421,8 +424,8 @@ bool BufferStateLayer::setBuffer(const std::shared_ptrgetBuffer()->getWidth(); - mCurrentState.height = mCurrentState.buffer->getBuffer()->getHeight(); + mCurrentState.width = mCurrentState.buffer->width; + mCurrentState.height = mCurrentState.buffer->height; return true; } @@ -671,7 +674,7 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse } const int32_t layerId = getSequence(); - const uint64_t bufferId = mDrawingState.buffer->getBuffer()->getId(); + const uint64_t bufferId = mDrawingState.buffer->getId(); const uint64_t frameNumber = mDrawingState.frameNumber; const auto acquireFence = std::make_shared(mDrawingState.acquireFence); mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence); @@ -705,7 +708,7 @@ status_t BufferStateLayer::updateActiveBuffer() { return BAD_VALUE; } - if (!mBufferInfo.mBuffer || s.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) { + if (s.buffer != mBufferInfo.mBuffer) { decrementPendingBufferCount(); } @@ -824,13 +827,13 @@ uint32_t BufferStateLayer::getEffectiveScalingMode() const { Rect BufferStateLayer::computeCrop(const State& s) { if (s.crop.isEmpty() && s.buffer) { - return s.buffer->getBuffer()->getBounds(); + return s.buffer->getBounds(); } else if (s.buffer) { Rect crop = s.crop; crop.left = std::max(crop.left, 0); crop.top = std::max(crop.top, 0); - uint32_t bufferWidth = s.buffer->getBuffer()->getWidth(); - uint32_t bufferHeight = s.buffer->getBuffer()->getHeight(); + uint32_t bufferWidth = s.buffer->getWidth(); + uint32_t bufferHeight = s.buffer->getHeight(); if (bufferHeight <= std::numeric_limits::max() && bufferWidth <= std::numeric_limits::max()) { crop.right = std::min(crop.right, static_cast(bufferWidth)); @@ -838,7 +841,7 @@ Rect BufferStateLayer::computeCrop(const State& s) { } if (!crop.isValid()) { // Crop rect is out of bounds, return whole buffer - return s.buffer->getBuffer()->getBounds(); + return s.buffer->getBounds(); } return crop; } @@ -860,8 +863,8 @@ bool BufferStateLayer::bufferNeedsFiltering() const { return false; } - uint32_t bufferWidth = s.buffer->getBuffer()->width; - uint32_t bufferHeight = s.buffer->getBuffer()->height; + uint32_t bufferWidth = s.buffer->width; + uint32_t bufferHeight = s.buffer->height; // Undo any transformations on the buffer and return the result. if (s.bufferTransform & ui::Transform::ROT_90) { @@ -888,16 +891,14 @@ void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) { ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers); } -void BufferStateLayer::bufferMayChange(const sp& newBuffer) { - if (mDrawingState.buffer != nullptr && - (!mBufferInfo.mBuffer || - mDrawingState.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) && - newBuffer != mDrawingState.buffer->getBuffer()) { +void BufferStateLayer::bufferMayChange(sp& newBuffer) { + if (mDrawingState.buffer != nullptr && mDrawingState.buffer != mBufferInfo.mBuffer && + newBuffer != mDrawingState.buffer) { // If we are about to update mDrawingState.buffer but it has not yet latched // then we will drop a buffer and should decrement the pending buffer count and // call any release buffer callbacks if set. - callReleaseBufferCallback(mDrawingState.releaseBufferListener, - mDrawingState.buffer->getBuffer(), mDrawingState.acquireFence); + callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer, + mDrawingState.acquireFence); decrementPendingBufferCount(); } } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index a69d07f634..8ce3e1f55b 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -66,9 +66,9 @@ public: bool setTransform(uint32_t transform) override; bool setTransformToDisplayInverse(bool transformToDisplayInverse) override; bool setCrop(const Rect& crop) override; - bool setBuffer(const std::shared_ptr& buffer, - const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, - bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, + bool setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, + nsecs_t desiredPresentTime, bool isAutoTimestamp, + const client_cache_t& clientCacheId, uint64_t frameNumber, std::optional dequeueTime, const FrameTimelineInfo& info, const sp& transactionListener) override; bool setAcquireFence(const sp& fence) override; @@ -108,7 +108,7 @@ public: // See mPendingBufferTransactions void decrementPendingBufferCount(); - void bufferMayChange(const sp& newBuffer) override; + void bufferMayChange(sp& newBuffer) override; std::atomic* getPendingBufferCounter() override { return &mPendingBufferTransactions; } std::string getPendingBufferCounterName() override { return mBlastTransactionName; } diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp index f310738423..44b33ef43d 100644 --- a/services/surfaceflinger/ClientCache.cpp +++ b/services/surfaceflinger/ClientCache.cpp @@ -102,12 +102,7 @@ bool ClientCache::add(const client_cache_t& cacheId, const sp& bu return false; } - LOG_ALWAYS_FATAL_IF(mRenderEngine == nullptr, - "Attempted to build the ClientCache before a RenderEngine instance was " - "ready!"); - processBuffers[id].buffer = std::make_shared< - renderengine::ExternalTexture>(buffer, *mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE); + processBuffers[id].buffer = buffer; return true; } @@ -137,7 +132,7 @@ void ClientCache::erase(const client_cache_t& cacheId) { } } -std::shared_ptr ClientCache::get(const client_cache_t& cacheId) { +sp ClientCache::get(const client_cache_t& cacheId) { std::lock_guard lock(mMutex); ClientCacheBuffer* buf = nullptr; @@ -218,8 +213,8 @@ void ClientCache::dump(std::string& result) { auto &buffers = i.second.second; for (auto& [id, clientCacheBuffer] : buffers) { StringAppendF(&result, "\t ID: %d, Width/Height: %d,%d\n", (int)id, - (int)clientCacheBuffer.buffer->getBuffer()->getWidth(), - (int)clientCacheBuffer.buffer->getBuffer()->getHeight()); + (int)clientCacheBuffer.buffer->getWidth(), + (int)clientCacheBuffer.buffer->getHeight()); } } } diff --git a/services/surfaceflinger/ClientCache.h b/services/surfaceflinger/ClientCache.h index a9b8177d70..0d597c8e05 100644 --- a/services/surfaceflinger/ClientCache.h +++ b/services/surfaceflinger/ClientCache.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -40,11 +39,7 @@ public: bool add(const client_cache_t& cacheId, const sp& buffer); void erase(const client_cache_t& cacheId); - std::shared_ptr get(const client_cache_t& cacheId); - - // Always called immediately after setup. Will be set to non-null, and then should never be - // called again. - void setRenderEngine(renderengine::RenderEngine* renderEngine) { mRenderEngine = renderEngine; } + sp get(const client_cache_t& cacheId); void removeProcess(const wp& processToken); @@ -64,7 +59,7 @@ private: std::mutex mMutex; struct ClientCacheBuffer { - std::shared_ptr buffer; + sp buffer; std::set> recipients; }; std::map /*caching process*/, @@ -78,7 +73,6 @@ private: }; sp mDeathRecipient; - renderengine::RenderEngine* mRenderEngine = nullptr; bool getBuffer(const client_cache_t& cacheId, ClientCacheBuffer** outClientCacheBuffer) REQUIRES(mMutex); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index daee83bd2c..f680460242 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -16,16 +16,15 @@ #pragma once -#include +#include +#include + #include #include #include #include #include -#include -#include - namespace android { class GraphicBuffer; @@ -81,8 +80,7 @@ public: virtual void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) = 0; // Allocates a buffer as scratch space for GPU composition - virtual std::shared_ptr dequeueBuffer( - base::unique_fd* bufferFence) = 0; + virtual sp dequeueBuffer(base::unique_fd* bufferFence) = 0; // Queues the drawn buffer for consumption by HWC. readyFence is the fence // which will fire when the buffer is ready for consumption. diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h index a8d372c562..a1230b3c4d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h @@ -45,8 +45,6 @@ struct RenderSurfaceCreationArgs { // The DisplaySurface for this surface sp displaySurface; - - size_t maxTextureCacheSize; }; /** @@ -83,11 +81,6 @@ public: return *this; } - RenderSurfaceCreationArgsBuilder& setMaxTextureCacheSize(size_t maxTextureCacheSize) { - mArgs.maxTextureCacheSize = maxTextureCacheSize; - return *this; - } - private: RenderSurfaceCreationArgs mArgs; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index c61ec5991b..48a54d6c66 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -89,7 +89,7 @@ struct OutputLayerCompositionState { // Overrides the buffer, acquire fence, and display frame stored in LayerFECompositionState struct { - std::shared_ptr buffer = nullptr; + sp buffer = nullptr; sp acquireFence = nullptr; Rect displayFrame = {}; ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index a8a538003e..5127a6f314 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -16,16 +16,12 @@ #pragma once +#include + #include #include #include -#include -#include - -#include "renderengine/ExternalTexture.h" -#include "renderengine/RenderEngine.h" - struct ANativeWindow; namespace android { @@ -58,8 +54,7 @@ public: void setProtected(bool useProtected) override; status_t beginFrame(bool mustRecompose) override; void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) override; - std::shared_ptr dequeueBuffer( - base::unique_fd* bufferFence) override; + sp dequeueBuffer(base::unique_fd* bufferFence) override; void queueBuffer(base::unique_fd readyFence) override; void onPresentDisplayCompleted() override; void flip() override; @@ -71,7 +66,7 @@ public: // Testing void setPageFlipCountForTest(std::uint32_t); void setSizeForTest(const ui::Size&); - std::shared_ptr& mutableTextureForTest(); + sp& mutableGraphicBufferForTest(); base::unique_fd& mutableBufferReadyForTest(); private: @@ -80,13 +75,10 @@ private: // ANativeWindow being rendered into const sp mNativeWindow; - - std::vector> mTextureCache; - // Current texture being rendered into - std::shared_ptr mTexture; + // Current buffer being rendered into + sp mGraphicBuffer; const sp mDisplaySurface; ui::Size mSize; - const size_t mMaxTextureCacheSize; bool mProtected{false}; std::uint32_t mPageFlipCount{0}; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h index 53f4a30fb8..c5d03a7218 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h @@ -66,7 +66,7 @@ public: const Rect& getBounds() const { return mBounds; } const Region& getVisibleRegion() const { return mVisibleRegion; } size_t getAge() const { return mAge; } - const std::shared_ptr& getBuffer() const { return mTexture; } + const sp& getBuffer() const { return mTexture.getBuffer(); } const sp& getDrawFence() const { return mDrawFence; } const ProjectionSpace& getOutputSpace() const { return mOutputSpace; } ui::Dataspace getOutputDataspace() const { return mOutputDataspace; } @@ -87,7 +87,7 @@ public: void setLastUpdate(std::chrono::steady_clock::time_point now) { mLastUpdate = now; } void append(const CachedSet& other) { - mTexture = nullptr; + mTexture.setBuffer(nullptr, nullptr); mOutputDataspace = ui::Dataspace::UNKNOWN; mDrawFence = nullptr; @@ -115,7 +115,31 @@ private: Region mVisibleRegion; size_t mAge = 0; - std::shared_ptr mTexture; + class Texture { + public: + ~Texture() { setBuffer(nullptr, nullptr); } + + void setBuffer(const sp& buffer, renderengine::RenderEngine* re) { + if (mRE && mBuffer) { + mRE->unbindExternalTextureBuffer(mBuffer->getId()); + } + + mBuffer = buffer; + mRE = re; + + if (mRE && mBuffer) { + mRE->cacheExternalTextureBuffer(mBuffer); + } + } + + const sp& getBuffer() const { return mBuffer; } + + private: + sp mBuffer = nullptr; + renderengine::RenderEngine* mRE = nullptr; + }; + + Texture mTexture; sp mDrawFence; ProjectionSpace mOutputSpace; ui::Dataspace mOutputDataspace; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index fe858c2817..a0cae6fcbb 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -39,7 +39,7 @@ public: MOCK_METHOD1(setBufferPixelFormat, void(ui::PixelFormat)); MOCK_METHOD1(beginFrame, status_t(bool mustRecompose)); MOCK_METHOD2(prepareFrame, void(bool, bool)); - MOCK_METHOD1(dequeueBuffer, std::shared_ptr(base::unique_fd*)); + MOCK_METHOD1(dequeueBuffer, sp(base::unique_fd*)); MOCK_METHOD1(queueBuffer, void(base::unique_fd)); MOCK_METHOD0(onPresentDisplayCompleted, void()); MOCK_METHOD0(flip, void()); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 3468b204fc..3ac5433457 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ -#include +#include + #include #include #include @@ -28,9 +29,7 @@ #include #include -#include - -#include "renderengine/ExternalTexture.h" +#include // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push @@ -716,11 +715,11 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr bool skipLayer = false; if (layer->getState().overrideInfo.buffer != nullptr) { if (previousOverride != nullptr && - layer->getState().overrideInfo.buffer->getBuffer() == previousOverride) { + layer->getState().overrideInfo.buffer == previousOverride) { ALOGV("Skipping redundant buffer"); skipLayer = true; } - previousOverride = layer->getState().overrideInfo.buffer->getBuffer(); + previousOverride = layer->getState().overrideInfo.buffer; } const bool includeGeometry = refreshArgs.updatingGeometryThisFrame; @@ -979,15 +978,14 @@ std::optional Output::composeSurfaces( } base::unique_fd fd; - - std::shared_ptr tex; + sp buf; // If we aren't doing client composition on this output, but do have a // flipClientTarget request for this frame on this output, we still need to // dequeue a buffer. if (hasClientComposition || outputState.flipClientTarget) { - tex = mRenderSurface->dequeueBuffer(&fd); - if (tex == nullptr) { + buf = mRenderSurface->dequeueBuffer(&fd); + if (buf == nullptr) { ALOGW("Dequeuing buffer for display [%s] failed, bailing out of " "client composition for this frame", mName.c_str()); @@ -1032,14 +1030,13 @@ std::optional Output::composeSurfaces( // Check if the client composition requests were rendered into the provided graphic buffer. If // so, we can reuse the buffer and avoid client composition. if (mClientCompositionRequestCache) { - if (mClientCompositionRequestCache->exists(tex->getBuffer()->getId(), - clientCompositionDisplay, + if (mClientCompositionRequestCache->exists(buf->getId(), clientCompositionDisplay, clientCompositionLayers)) { outputCompositionState.reusedClientComposition = true; setExpensiveRenderingExpected(false); return readyFence; } - mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay, + mClientCompositionRequestCache->add(buf->getId(), clientCompositionDisplay, clientCompositionLayers); } @@ -1072,12 +1069,12 @@ std::optional Output::composeSurfaces( // over to RenderEngine, in which case this flag can be removed from the drawLayers interface. const bool useFramebufferCache = outputState.layerStackInternal; status_t status = - renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex, + renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buf, useFramebufferCache, std::move(fd), &readyFence); if (status != NO_ERROR && mClientCompositionRequestCache) { // If rendering was not successful, remove the request from the cache. - mClientCompositionRequestCache->remove(tex->getBuffer()->getId()); + mClientCompositionRequestCache->remove(buf->getId()); } auto& timeStats = getCompositionEngine().getTimeStats(); @@ -1154,9 +1151,9 @@ std::vector Output::generateClientCompositionRequests( std::vector results; if (layer->getState().overrideInfo.buffer != nullptr) { - if (layer->getState().overrideInfo.buffer->getBuffer() != previousOverrideBuffer) { + if (layer->getState().overrideInfo.buffer != previousOverrideBuffer) { results = layer->getOverrideCompositionList(); - previousOverrideBuffer = layer->getState().overrideInfo.buffer->getBuffer(); + previousOverrideBuffer = layer->getState().overrideInfo.buffer; ALOGV("Replacing [%s] with override in RE", layer->getLayerFE().getDebugName()); } else { ALOGV("Skipping redundant override buffer for [%s] in RE", diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 9ca8914deb..f640f85bca 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -537,7 +537,7 @@ void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer, sp buffer = outputIndependentState.buffer; sp acquireFence = outputIndependentState.acquireFence; if (getState().overrideInfo.buffer != nullptr) { - buffer = getState().overrideInfo.buffer->getBuffer(); + buffer = getState().overrideInfo.buffer; acquireFence = getState().overrideInfo.acquireFence; } @@ -699,7 +699,7 @@ std::vector OutputLayer::getOverrideCompositionList() co settings.geometry = renderengine::Geometry{ .boundaries = boundaries.toFloatRect(), }; - settings.bufferId = getState().overrideInfo.buffer->getBuffer()->getId(); + settings.bufferId = getState().overrideInfo.buffer->getId(); settings.source = renderengine::PixelSource{ .buffer = renderengine::Buffer{ .buffer = getState().overrideInfo.buffer, diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index ef50870615..3bef77dde1 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -25,8 +25,8 @@ #include #include #include + #include -#include #include #include #include @@ -63,8 +63,7 @@ RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display mDisplay(display), mNativeWindow(args.nativeWindow), mDisplaySurface(args.displaySurface), - mSize(args.displayWidth, args.displayHeight), - mMaxTextureCacheSize(args.maxTextureCacheSize) { + mSize(args.displayWidth, args.displayHeight) { LOG_ALWAYS_FATAL_IF(!mNativeWindow); } @@ -147,8 +146,7 @@ void RenderSurface::prepareFrame(bool usesClientComposition, bool usesDeviceComp } } -std::shared_ptr RenderSurface::dequeueBuffer( - base::unique_fd* bufferFence) { +sp RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) { ATRACE_CALL(); int fd = -1; ANativeWindowBuffer* buffer = nullptr; @@ -160,41 +158,16 @@ std::shared_ptr RenderSurface::dequeueBuffer( mDisplay.getName().c_str(), result); // Return fast here as we can't do much more - any rendering we do // now will just be wrong. - return mTexture; - } - - ALOGW_IF(mTexture != nullptr, "Clobbering a non-null pointer to a buffer [%p].", - mTexture->getBuffer()->getNativeBuffer()->handle); - - sp newBuffer = GraphicBuffer::from(buffer); - - std::shared_ptr texture; - - for (auto it = mTextureCache.begin(); it != mTextureCache.end(); it++) { - const auto& cachedTexture = *it; - if (cachedTexture->getBuffer()->getId() == newBuffer->getId()) { - texture = cachedTexture; - mTextureCache.erase(it); - break; - } + return mGraphicBuffer; } - if (texture) { - mTexture = texture; - } else { - mTexture = std::make_shared< - renderengine::ExternalTexture>(GraphicBuffer::from(buffer), - mCompositionEngine.getRenderEngine(), - renderengine::ExternalTexture::Usage::WRITEABLE); - } - mTextureCache.push_back(mTexture); - if (mTextureCache.size() > mMaxTextureCacheSize) { - mTextureCache.erase(mTextureCache.begin()); - } + ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].", + mGraphicBuffer->getNativeBuffer()->handle); + mGraphicBuffer = GraphicBuffer::from(buffer); *bufferFence = base::unique_fd(fd); - return mTexture; + return mGraphicBuffer; } void RenderSurface::queueBuffer(base::unique_fd readyFence) { @@ -204,24 +177,24 @@ void RenderSurface::queueBuffer(base::unique_fd readyFence) { // hasFlipClientTargetRequest could return true even if we haven't // dequeued a buffer before. Try dequeueing one if we don't have a // buffer ready. - if (mTexture == nullptr) { + if (mGraphicBuffer == nullptr) { ALOGI("Attempting to queue a client composited buffer without one " "previously dequeued for display [%s]. Attempting to dequeue " "a scratch buffer now", mDisplay.getName().c_str()); - // We shouldn't deadlock here, since mTexture == nullptr only + // We shouldn't deadlock here, since mGraphicBuffer == nullptr only // after a successful call to queueBuffer, or if dequeueBuffer has // never been called. base::unique_fd unused; dequeueBuffer(&unused); } - if (mTexture == nullptr) { + if (mGraphicBuffer == nullptr) { ALOGE("No buffer is ready for display [%s]", mDisplay.getName().c_str()); } else { - status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(), - mTexture->getBuffer()->getNativeBuffer(), - dup(readyFence)); + status_t result = + mNativeWindow->queueBuffer(mNativeWindow.get(), + mGraphicBuffer->getNativeBuffer(), dup(readyFence)); if (result != NO_ERROR) { ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(), result); @@ -231,12 +204,11 @@ void RenderSurface::queueBuffer(base::unique_fd readyFence) { LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result); } else { mNativeWindow->cancelBuffer(mNativeWindow.get(), - mTexture->getBuffer()->getNativeBuffer(), - dup(readyFence)); + mGraphicBuffer->getNativeBuffer(), dup(readyFence)); } } - mTexture = nullptr; + mGraphicBuffer = nullptr; } } @@ -284,8 +256,8 @@ void RenderSurface::setSizeForTest(const ui::Size& size) { mSize = size; } -std::shared_ptr& RenderSurface::mutableTextureForTest() { - return mTexture; +sp& RenderSurface::mutableGraphicBufferForTest() { + return mGraphicBuffer; } } // namespace impl diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index 53557bbb9f..dcb75556e3 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -130,7 +130,7 @@ bool CachedSet::hasBufferUpdate() const { } bool CachedSet::hasReadyBuffer() const { - return mTexture != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled; + return mTexture.getBuffer() != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled; } std::vector CachedSet::decompose() const { @@ -217,27 +217,21 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, sp buffer = new GraphicBuffer(static_cast(mBounds.getWidth()), static_cast(mBounds.getHeight()), HAL_PIXEL_FORMAT_RGBA_8888, 1, usageFlags); - const auto texture = std::make_shared< - renderengine::ExternalTexture>(buffer, renderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); LOG_ALWAYS_FATAL_IF(buffer->initCheck() != OK); base::unique_fd drawFence; - status_t result = renderEngine.drawLayers(displaySettings, layerSettingsPointers, mTexture, - false, base::unique_fd(), &drawFence); + status_t result = renderEngine.drawLayers(displaySettings, layerSettingsPointers, buffer, false, + base::unique_fd(), &drawFence); if (result == NO_ERROR) { + mTexture.setBuffer(buffer, &renderEngine); mDrawFence = new Fence(drawFence.release()); mOutputSpace = ProjectionSpace(ui::Size(outputState.framebufferSpace.bounds.getWidth(), outputState.framebufferSpace.bounds.getHeight()), mBounds); - mTexture = std::move(texture); mOutputSpace.orientation = outputState.framebufferSpace.orientation; mOutputDataspace = outputDataspace; mOrientation = orientation; - } else { - mTexture = nullptr; } } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp index 3a2534b847..ad7555730d 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp @@ -111,12 +111,7 @@ void Planner::reportFinalPlan( const GraphicBuffer* currentOverrideBuffer = nullptr; bool hasSkippedLayers = false; for (auto layer : layers) { - if (!layer->getState().overrideInfo.buffer) { - continue; - } - - const GraphicBuffer* overrideBuffer = - layer->getState().overrideInfo.buffer->getBuffer().get(); + const GraphicBuffer* overrideBuffer = layer->getState().overrideInfo.buffer.get(); if (overrideBuffer != nullptr && overrideBuffer == currentOverrideBuffer) { // Skip this layer since it is part of a previous cached set hasSkippedLayers = true; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 4c3f4940cc..8a4d161289 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -26,7 +26,6 @@ #include "MockHWC2.h" #include "MockHWComposer.h" #include "RegionMatcher.h" -#include "renderengine/mock/RenderEngine.h" namespace android::compositionengine { namespace { @@ -716,7 +715,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static const HdrMetadata kHdrMetadata; static native_handle_t* kSidebandStreamHandle; static const sp kBuffer; - std::shared_ptr kOverrideBuffer; + static const sp kOverrideBuffer; static const sp kFence; static const sp kOverrideFence; static const std::string kLayerGenericMetadata1Key; @@ -725,11 +724,6 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static const std::vector kLayerGenericMetadata2Value; OutputLayerWriteStateToHWCTest() { - kOverrideBuffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage:: - WRITEABLE); auto& outputLayerState = mOutputLayer.editState(); outputLayerState.hwc = impl::OutputLayerCompositionState::Hwc(mHwcLayer); @@ -845,7 +839,6 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { std::shared_ptr mHwcLayer{std::make_shared>()}; StrictMock mDisplayColorProfile; - renderengine::mock::RenderEngine mRenderEngine; }; const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 83.f / 255.f, @@ -865,6 +858,7 @@ const HdrMetadata OutputLayerWriteStateToHWCTest::kHdrMetadata{{/* LightFlattena native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle = reinterpret_cast(1031); const sp OutputLayerWriteStateToHWCTest::kBuffer; +const sp OutputLayerWriteStateToHWCTest::kOverrideBuffer = new GraphicBuffer(); const sp OutputLayerWriteStateToHWCTest::kFence; const sp OutputLayerWriteStateToHWCTest::kOverrideFence = new Fence(); const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key = @@ -1029,7 +1023,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { kOverrideBufferTransform, kOverrideBlendMode, kOverrideAlpha); expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion, kOverrideSurfaceDamage); - expectSetHdrMetadataAndBufferCalls(kOverrideBuffer->getBuffer(), kOverrideFence); + expectSetHdrMetadataAndBufferCalls(kOverrideBuffer, kOverrideFence); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index e80100cc6e..5f0b0eea15 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #include #include #include @@ -29,12 +31,9 @@ #include #include -#include - #include "CallOrderStateMachineHelper.h" #include "MockHWC2.h" #include "RegionMatcher.h" -#include "renderengine/ExternalTexture.h" namespace android::compositionengine { namespace { @@ -2961,10 +2960,7 @@ struct OutputComposeSurfacesTest : public testing::Test { mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock(); mock::RenderSurface* mRenderSurface = new StrictMock(); StrictMock mOutput; - std::shared_ptr mOutputBuffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + sp mOutputBuffer = new GraphicBuffer(); std::optional mReadyFence; }; @@ -3177,10 +3173,7 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) { EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _)) .WillRepeatedly(Return()); - const auto otherOutputBuffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); + sp otherOutputBuffer = new GraphicBuffer(); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)) .WillOnce(Return(mOutputBuffer)) .WillOnce(Return(otherOutputBuffer)); diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 9aeb290eb5..5ef5d7b5cb 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -15,8 +15,6 @@ */ // TODO(b/129481165): remove the #pragma below and fix conversion issues -#include "renderengine/ExternalTexture.h" -#include "ui/GraphicBuffer.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wextra" @@ -241,9 +239,9 @@ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) { DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR))); base::unique_fd fence; - EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer(&fence)->getBuffer().get()); + EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer(&fence).get()); - EXPECT_EQ(buffer.get(), mSurface.mutableTextureForTest()->getBuffer().get()); + EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get()); } /* @@ -251,11 +249,8 @@ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) { */ TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { - const auto buffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, - renderengine::ExternalTexture::Usage::READABLE | - renderengine::ExternalTexture::Usage::WRITEABLE); - mSurface.mutableTextureForTest() = buffer; + sp buffer = new GraphicBuffer(); + mSurface.mutableGraphicBufferForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = false; @@ -266,45 +261,43 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(buffer.get(), mSurface.mutableTextureForTest().get()); + EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) { - const auto buffer = std::make_shared(new GraphicBuffer(), - mRenderEngine, false); - mSurface.mutableTextureForTest() = buffer; + sp buffer = new GraphicBuffer(); + mSurface.mutableGraphicBufferForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = true; state.flipClientTarget = false; EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); - EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) { - const auto buffer = std::make_shared(new GraphicBuffer(), - mRenderEngine, false); - mSurface.mutableTextureForTest() = buffer; + sp buffer = new GraphicBuffer(); + mSurface.mutableGraphicBufferForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = false; state.flipClientTarget = true; EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); - EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) { @@ -324,28 +317,27 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferY mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) { - const auto buffer = std::make_shared(new GraphicBuffer(), - mRenderEngine, false); - mSurface.mutableTextureForTest() = buffer; + sp buffer = new GraphicBuffer(); + mSurface.mutableGraphicBufferForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = true; EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); - EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) .WillOnce(Return(INVALID_OPERATION)); EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true)); - EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index 283c69270f..f01fe27b38 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -305,8 +305,8 @@ TEST_F(CachedSetTest, render) { const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, const std::vector& layers, - const std::shared_ptr&, const bool, - base::unique_fd&&, base::unique_fd*) -> size_t { + const sp&, const bool, base::unique_fd&&, + base::unique_fd*) -> size_t { EXPECT_EQ(Rect(0, 0, 2, 2), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation), @@ -321,6 +321,7 @@ TEST_F(CachedSetTest, render) { EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1)); EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers)); + EXPECT_CALL(mRenderEngine, cacheExternalTextureBuffer(_)); cachedSet.render(mRenderEngine, mOutputState); expectReadyBuffer(cachedSet); @@ -330,6 +331,7 @@ TEST_F(CachedSetTest, render) { cachedSet.getOutputSpace().bounds); // Now check that appending a new cached set properly cleans up RenderEngine resources. + EXPECT_CALL(mRenderEngine, unbindExternalTextureBuffer(_)); CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get(); cachedSet.append(CachedSet(layer3)); } diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 8692ee60dc..b7b2cc691b 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -70,13 +70,11 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) mIsPrimary(args.isPrimary) { mCompositionDisplay->editState().isSecure = args.isSecure; mCompositionDisplay->createRenderSurface( - compositionengine:: - RenderSurfaceCreationArgs{ANativeWindow_getWidth(args.nativeWindow.get()), - ANativeWindow_getHeight(args.nativeWindow.get()), - args.nativeWindow, args.displaySurface, - static_cast( - SurfaceFlinger:: - maxFrameBufferAcquiredBuffers)}); + compositionengine::RenderSurfaceCreationArgs{ANativeWindow_getWidth( + args.nativeWindow.get()), + ANativeWindow_getHeight( + args.nativeWindow.get()), + args.nativeWindow, args.displaySurface}); if (!mFlinger->mDisableClientCompositionCache && SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b12e3fb626..829b91676b 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1050,7 +1050,7 @@ uint32_t Layer::doTransaction(uint32_t flags) { } // Allow BufferStateLayer to release any unlatched buffers in drawing state. - bufferMayChange(c.buffer->getBuffer()); + bufferMayChange(c.buffer); // Commit the transaction commitTransaction(c); @@ -1062,11 +1062,7 @@ uint32_t Layer::doTransaction(uint32_t flags) { void Layer::commitTransaction(State& stateToCommit) { if (auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX; - ((mDrawingState.buffer && stateToCommit.buffer && - mDrawingState.buffer->getBuffer() != stateToCommit.buffer->getBuffer()) || - (mDrawingState.buffer && !stateToCommit.buffer) || - (!mDrawingState.buffer && stateToCommit.buffer)) && - bufferSurfaceFrame != nullptr && + mDrawingState.buffer != stateToCommit.buffer && bufferSurfaceFrame != nullptr && bufferSurfaceFrame->getPresentState() != PresentState::Presented) { // If the previous buffer was committed but not latched (refreshPending - happens during // back to back invalidates), it gets silently dropped here. Mark the corresponding diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 8e51e4139b..64986afd61 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -208,7 +208,7 @@ public: Region transparentRegionHint; - std::shared_ptr buffer; + sp buffer; client_cache_t clientCacheId; sp acquireFence; std::shared_ptr acquireFenceTime; @@ -412,11 +412,10 @@ public: // Used only to set BufferStateLayer state virtual bool setTransform(uint32_t /*transform*/) { return false; }; virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; }; - virtual bool setBuffer(const std::shared_ptr& /*buffer*/, - const sp& /*acquireFence*/, nsecs_t /*postTime*/, - nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, - const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */, - std::optional /* dequeueTime */, + virtual bool setBuffer(const sp& /*buffer*/, const sp& /*acquireFence*/, + nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, + bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/, + uint64_t /* frameNumber */, std::optional /* dequeueTime */, const FrameTimelineInfo& /*info*/, const sp& /* releaseBufferListener */) { return false; @@ -727,7 +726,7 @@ public: * Called before updating the drawing state buffer. Used by BufferStateLayer to release any * unlatched buffers in the drawing state. */ - virtual void bufferMayChange(const sp& /* newBuffer */){}; + virtual void bufferMayChange(sp& /* newBuffer */){}; /* * Remove relative z for the layer if its relative parent is not part of the diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index a9fd16cb75..7a3e433660 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -208,8 +208,7 @@ bool RefreshRateOverlay::createLayer() { return true; } -const std::vector>& -RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { +const std::vector>& RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { if (mBufferCache.find(fps) == mBufferCache.end()) { // Ensure the range is > 0, so we don't divide by 0. const auto rangeLength = std::max(1u, mHighFps - mLowFps); @@ -223,17 +222,7 @@ RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale); color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale); color.a = ALPHA; - auto buffers = SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner); - std::vector> textures; - std::transform(buffers.begin(), buffers.end(), std::back_inserter(textures), - [&](const auto& buffer) -> std::shared_ptr { - return std::make_shared< - renderengine::ExternalTexture>(buffer, - mFlinger.getRenderEngine(), - renderengine::ExternalTexture:: - Usage::READABLE); - }); - mBufferCache.emplace(fps, textures); + mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner)); } return mBufferCache[fps]; diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index aa8329c46a..c16cfa07a4 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -16,14 +16,13 @@ #pragma once +#include + #include -#include #include #include #include -#include - #include "Fps.h" namespace android { @@ -71,8 +70,7 @@ private: }; bool createLayer(); - const std::vector>& getOrCreateBuffers( - uint32_t fps); + const std::vector>& getOrCreateBuffers(uint32_t fps); SurfaceFlinger& mFlinger; const sp mClient; @@ -80,8 +78,7 @@ private: sp mIBinder; sp mGbp; - std::unordered_map>> - mBufferCache; + std::unordered_map>> mBufferCache; std::optional mCurrentFps; int mFrame = 0; static constexpr float ALPHA = 0.8f; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 00090d948a..d0032ac7fd 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -438,22 +438,18 @@ void RegionSamplingThread::captureSample() { mFlinger.traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, filterVisitor); }; - std::shared_ptr buffer = nullptr; - if (mCachedBuffer && mCachedBuffer->getBuffer()->getWidth() == sampledBounds.getWidth() && - mCachedBuffer->getBuffer()->getHeight() == sampledBounds.getHeight()) { + sp buffer = nullptr; + if (mCachedBuffer && mCachedBuffer->getWidth() == sampledBounds.getWidth() && + mCachedBuffer->getHeight() == sampledBounds.getHeight()) { buffer = mCachedBuffer; } else { const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - sp graphicBuffer = - new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), - PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); - const status_t bufferStatus = graphicBuffer->initCheck(); + buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), + PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); + const status_t bufferStatus = buffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d", bufferStatus); - buffer = std::make_shared< - renderengine::ExternalTexture>(graphicBuffer, mFlinger.getRenderEngine(), - renderengine::ExternalTexture::Usage::WRITEABLE); } const sp captureListener = new SyncScreenCaptureListener(); @@ -469,8 +465,8 @@ void RegionSamplingThread::captureSample() { } ALOGV("Sampling %zu descriptors", activeDescriptors.size()); - std::vector lumas = sampleBuffer(buffer->getBuffer(), sampledBounds.leftTop(), - activeDescriptors, orientation); + std::vector lumas = + sampleBuffer(buffer, sampledBounds.leftTop(), activeDescriptors, orientation); if (lumas.size() != activeDescriptors.size()) { ALOGW("collected %zu median luma values for %zu descriptors", lumas.size(), activeDescriptors.size()); @@ -481,6 +477,16 @@ void RegionSamplingThread::captureSample() { activeDescriptors[d].listener->onSampleCollected(lumas[d]); } + // Extend the lifetime of mCachedBuffer from the previous frame to here to ensure that: + // 1) The region sampling thread is the last owner of the buffer, and the freeing of the buffer + // happens in this thread, as opposed to the main thread. + // 2) The listener(s) receive their notifications prior to freeing the buffer. + if (mCachedBuffer != nullptr && mCachedBuffer != buffer) { + if (mFlinger.getRenderEngine().getRenderEngineType() == + renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) { + mFlinger.getRenderEngine().unbindExternalTextureBuffer(mCachedBuffer->getId()); + } + } mCachedBuffer = buffer; ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::noWorkNeeded)); } diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h index 86632db490..0defdb3fcb 100644 --- a/services/surfaceflinger/RegionSamplingThread.h +++ b/services/surfaceflinger/RegionSamplingThread.h @@ -16,19 +16,17 @@ #pragma once -#include -#include -#include -#include -#include -#include - #include #include #include #include #include +#include +#include +#include +#include +#include #include "Scheduler/OneShotTimer.h" namespace android { @@ -124,8 +122,7 @@ private: std::mutex mSamplingMutex; std::unordered_map, Descriptor, WpHash> mDescriptors GUARDED_BY(mSamplingMutex); - std::shared_ptr mCachedBuffer GUARDED_BY(mSamplingMutex) = - nullptr; + sp mCachedBuffer GUARDED_BY(mSamplingMutex) = nullptr; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e66f65b71e..02579c6bde 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -735,7 +735,6 @@ void SurfaceFlinger::init() { mCompositionEngine->setTimeStats(mTimeStats); mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName)); mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId); - ClientCache::getInstance().setRenderEngine(&getRenderEngine()); // Process any initial hotplug and resulting display changes. processDisplayHotplugEventsLocked(); const auto display = getDefaultDisplayDeviceLocked(); @@ -3708,6 +3707,7 @@ void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin if (uncacheBuffer.isValid()) { ClientCache::getInstance().erase(uncacheBuffer); + getRenderEngine().unbindExternalTextureBuffer(uncacheBuffer.id); } // If a synchronous transaction is explicitly requested without any changes, force a transaction @@ -4083,16 +4083,23 @@ uint32_t SurfaceFlinger::setClientStateLocked( } bool bufferChanged = what & layer_state_t::eBufferChanged; bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged; - std::shared_ptr buffer; + sp buffer; if (bufferChanged && cacheIdChanged && s.buffer != nullptr) { - ClientCache::getInstance().add(s.cachedBuffer, s.buffer); - buffer = ClientCache::getInstance().get(s.cachedBuffer); + buffer = s.buffer; + bool success = ClientCache::getInstance().add(s.cachedBuffer, s.buffer); + if (success) { + getRenderEngine().cacheExternalTextureBuffer(s.buffer); + success = ClientCache::getInstance() + .registerErasedRecipient(s.cachedBuffer, + wp(this)); + if (!success) { + getRenderEngine().unbindExternalTextureBuffer(s.buffer->getId()); + } + } } else if (cacheIdChanged) { buffer = ClientCache::getInstance().get(s.cachedBuffer); } else if (bufferChanged) { - buffer = std::make_shared< - renderengine::ExternalTexture>(s.buffer, getRenderEngine(), - renderengine::ExternalTexture::Usage::READABLE); + buffer = s.buffer; } if (buffer) { const bool frameNumberChanged = what & layer_state_t::eFrameNumberChanged; @@ -5996,17 +6003,15 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, const status_t bufferStatus = buffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d", bufferStatus); - const auto texture = std::make_shared< - renderengine::ExternalTexture>(buffer, getRenderEngine(), - renderengine::ExternalTexture::Usage::WRITEABLE); - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, texture, + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, false /* regionSampling */, grayscale, captureListener); } -status_t SurfaceFlinger::captureScreenCommon( - RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, - const std::shared_ptr& buffer, bool regionSampling, - bool grayscale, const sp& captureListener) { +status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, + TraverseLayersFunction traverseLayers, + sp& buffer, bool regionSampling, + bool grayscale, + const sp& captureListener) { ATRACE_CALL(); if (captureListener == nullptr) { @@ -6039,6 +6044,15 @@ status_t SurfaceFlinger::captureScreenCommon( regionSampling, grayscale, captureResults); }); + // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine + // Only do this when we're not doing region sampling, to allow the region sampling thread to + // manage buffer lifecycle itself. + if (!regionSampling && + getRenderEngine().getRenderEngineType() == + renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) { + getRenderEngine().unbindExternalTextureBuffer(buffer->getId()); + } + captureResults.result = result; captureListener->onScreenCaptureCompleted(captureResults); })); @@ -6046,10 +6060,11 @@ status_t SurfaceFlinger::captureScreenCommon( return NO_ERROR; } -status_t SurfaceFlinger::renderScreenImplLocked( - const RenderArea& renderArea, TraverseLayersFunction traverseLayers, - const std::shared_ptr& buffer, bool forSystem, - bool regionSampling, bool grayscale, ScreenCaptureResults& captureResults) { +status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, + TraverseLayersFunction traverseLayers, + const sp& buffer, bool forSystem, + bool regionSampling, bool grayscale, + ScreenCaptureResults& captureResults) { ATRACE_CALL(); traverseLayers([&](Layer* layer) { @@ -6057,7 +6072,7 @@ status_t SurfaceFlinger::renderScreenImplLocked( captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure()); }); - const bool useProtected = buffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED; + const bool useProtected = buffer->getUsage() & GRALLOC_USAGE_PROTECTED; // We allow the system server to take screenshots of secure layers for // use in situations like the Screen-rotation animation and place @@ -6067,7 +6082,7 @@ status_t SurfaceFlinger::renderScreenImplLocked( return PERMISSION_DENIED; } - captureResults.buffer = buffer->getBuffer(); + captureResults.buffer = buffer; captureResults.capturedDataspace = renderArea.getReqDataSpace(); const auto reqWidth = renderArea.getReqWidth(); @@ -6158,9 +6173,11 @@ status_t SurfaceFlinger::renderScreenImplLocked( base::unique_fd drawFence; getRenderEngine().useProtectedContext(useProtected); - const constexpr bool kUseFramebufferCache = false; + // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine + const bool useFramebufferCache = getRenderEngine().getRenderEngineType() == + renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED; getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer, - kUseFramebufferCache, std::move(bufferFence), &drawFence); + useFramebufferCache, std::move(bufferFence), &drawFence); if (drawFence >= 0) { sp releaseFence = new Fence(dup(drawFence)); @@ -6425,6 +6442,10 @@ void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) { mOffscreenLayers.erase(layer); } +void SurfaceFlinger::bufferErased(const client_cache_t& clientCacheId) { + getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id); +} + status_t SurfaceFlinger::setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a242d8a876..b3da61e810 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -184,6 +184,7 @@ public: class SurfaceFlinger : public BnSurfaceComposer, public PriorityDumper, + public ClientCache::ErasedRecipient, private IBinder::DeathRecipient, private HWC2::ComposerCallback, private ISchedulerCallback { @@ -331,6 +332,9 @@ public: wp fromHandle(const sp& handle); wp fromHandleLocked(const sp& handle) const REQUIRES(mStateLock); + // Inherit from ClientCache::ErasedRecipient + void bufferErased(const client_cache_t& clientCacheId) override; + // If set, disables reusing client composition buffers. This can be set by // debug.sf.disable_client_composition_cache bool mDisableClientCompositionCache = false; @@ -903,14 +907,12 @@ private: status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, ui::PixelFormat, bool allowProtected, bool grayscale, const sp&); - status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, - const std::shared_ptr&, + status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp&, bool regionSampling, bool grayscale, const sp&); status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction, - const std::shared_ptr&, - bool forSystem, bool regionSampling, bool grayscale, - ScreenCaptureResults&); + const sp&, bool forSystem, bool regionSampling, + bool grayscale, ScreenCaptureResults&); sp getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); sp getDisplayById(DisplayId displayId) const REQUIRES(mStateLock); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 3042450f29..4e1c0c77ea 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -15,7 +15,6 @@ */ // TODO(b/129481165): remove the #pragma below and fix conversion issues -#include "renderengine/ExternalTexture.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wextra" @@ -195,7 +194,7 @@ public: sp mClientTargetAcquireFence = Fence::NO_FENCE; - std::shared_ptr mCaptureScreenBuffer; + sp mCaptureScreenBuffer; }; template @@ -244,15 +243,11 @@ void CompositionTest::captureScreenComposition() { // TODO: Eliminate expensive/real allocation if possible. const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - mCaptureScreenBuffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(renderArea->getReqWidth(), - renderArea->getReqHeight(), - HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, - "screenshot"), - *mRenderEngine, true); + mCaptureScreenBuffer = new GraphicBuffer(renderArea->getReqWidth(), renderArea->getReqHeight(), + HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot"); status_t result = - mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer, + mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer.get(), forSystem, regionSampling); EXPECT_EQ(NO_ERROR, result); @@ -345,8 +340,8 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings, const std::vector&, - const std::shared_ptr&, - const bool, base::unique_fd&&, base::unique_fd*) -> status_t { + const sp&, const bool, base::unique_fd&&, + base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -394,8 +389,8 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings, const std::vector&, - const std::shared_ptr&, - const bool, base::unique_fd&&, base::unique_fd*) -> status_t { + const sp&, const bool, base::unique_fd&&, + base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -630,8 +625,8 @@ struct BaseLayerProperties { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings& displaySettings, const std::vector& layerSettings, - const std::shared_ptr&, const bool, - base::unique_fd&&, base::unique_fd*) -> status_t { + const sp&, const bool, base::unique_fd&&, + base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -679,8 +674,8 @@ struct BaseLayerProperties { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings& displaySettings, const std::vector& layerSettings, - const std::shared_ptr&, const bool, - base::unique_fd&&, base::unique_fd*) -> status_t { + const sp&, const bool, base::unique_fd&&, + base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -756,8 +751,8 @@ struct CommonSecureLayerProperties : public BaseLayerProperties EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings& displaySettings, const std::vector& layerSettings, - const std::shared_ptr&, const bool, - base::unique_fd&&, base::unique_fd*) -> status_t { + const sp&, const bool, base::unique_fd&&, + base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index d004b9d9eb..63baf7dee2 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -352,8 +352,8 @@ public: auto renderScreenImplLocked(const RenderArea& renderArea, SurfaceFlinger::TraverseLayersFunction traverseLayers, - const std::shared_ptr& buffer, - bool forSystem, bool regionSampling) { + const sp& buffer, bool forSystem, + bool regionSampling) { ScreenCaptureResults captureResults; return mFlinger->renderScreenImplLocked(renderArea, traverseLayers, buffer, forSystem, regionSampling, false /* grayscale */, diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index 690a7fd757..b5ef0a1334 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -21,8 +21,6 @@ #include #include #include -#include -#include #include #include "TestableSurfaceFlinger.h" @@ -104,7 +102,6 @@ public: TestableSurfaceFlinger mFlinger; Hwc2::mock::Composer* mComposer = nullptr; - renderengine::mock::RenderEngine mRenderEngine; FenceToFenceTimeMap fenceFactory; client_cache_t mClientCache; @@ -112,12 +109,9 @@ public: sp layer = createBufferStateLayer(); sp fence(new Fence()); - const auto buffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, 0), - mRenderEngine, false); + sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; int32_t layerId = layer->getSequence(); - uint64_t bufferId = buffer->getBuffer()->getId(); + uint64_t bufferId = buffer->getId(); uint64_t frameNumber = 5; nsecs_t dequeueTime = 10; nsecs_t postTime = 20; diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index 6ff6e908fa..c75538f476 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -21,8 +21,6 @@ #include #include #include -#include -#include #include #include "TestableSurfaceFlinger.h" @@ -106,7 +104,6 @@ public: TestableSurfaceFlinger mFlinger; Hwc2::mock::Composer* mComposer = nullptr; - renderengine::mock::RenderEngine mRenderEngine; FenceToFenceTimeMap fenceFactory; client_cache_t mClientCache; @@ -127,10 +124,7 @@ public: sp layer = createBufferStateLayer(); sp fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - const auto buffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, 0), - mRenderEngine, false); + sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence->signalForTest(12); @@ -155,10 +149,7 @@ public: sp fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - const auto buffer1 = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, 0), - mRenderEngine, false); + sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -167,10 +158,7 @@ public: sp fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - const auto buffer2 = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, 0), - mRenderEngine, false); + sp buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; nsecs_t start = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); @@ -208,10 +196,8 @@ public: sp fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - const auto buffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, 0), - mRenderEngine, false); + sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence->signalForTest(12); @@ -236,10 +222,8 @@ public: sp layer = createBufferStateLayer(); sp fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - const auto buffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, 0), - mRenderEngine, false); + sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -268,10 +252,8 @@ public: sp fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - const auto buffer = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, 0), - mRenderEngine, false); + sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -369,10 +351,7 @@ public: sp fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - const auto buffer1 = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, 0), - mRenderEngine, false); + sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); @@ -380,10 +359,7 @@ public: sp fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - const auto buffer2 = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, 0), - mRenderEngine, false); + sp buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence2->signalForTest(12); @@ -410,10 +386,7 @@ public: sp fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - const auto buffer1 = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, 0), - mRenderEngine, false); + sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -422,10 +395,7 @@ public: sp fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - const auto buffer2 = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, 0), - mRenderEngine, false); + sp buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; auto dropStartTime1 = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0}, @@ -437,10 +407,7 @@ public: sp fence3(new Fence()); auto acquireFence3 = fenceFactory.createFenceTimeForTest(fence3); - const auto buffer3 = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, - 1, 0), - mRenderEngine, false); + sp buffer3{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; auto dropStartTime2 = systemTime(); layer->setBuffer(buffer3, fence3, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); @@ -480,11 +447,7 @@ public: std::vector> bufferlessSurfaceFrames; for (int i = 0; i < 10; i += 2) { sp fence1(new Fence()); - const auto buffer1 = std::make_shared< - renderengine::ExternalTexture>(new GraphicBuffer(1, 1, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - 0), - mRenderEngine, false); + sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); -- cgit v1.2.3-59-g8ed1b From a90a570e5b35c72bc90bf20572dd989084c4db39 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 16 Apr 2021 16:36:21 +0000 Subject: Revert "Revert "Add ExternalTexture class into RenderEngine inte..." Revert submission 14199598-revert-14086921-renderengine-external-tex-QJNBWQMQEU Reason for revert: Prepare for relanding Reverted Changes: I01e65a7f4:Revert "Update WaylandRenderSurface to accomodate ... I7d58118c1:Revert "Update Readback VTS to align with RenderEn... I1501890f4:Revert "Add ExternalTexture class into RenderEngin... Added the following fixes: 1. CachedSet renders to intermediate texture variable rather than mTexture directly, since mTexture is not guaranteed to be nonnull. 2. Add null check when setting new buffer in BLAST. Bug: 185524947 Bug: 180767535 Test: builds, boots Test: librenderengine_test Change-Id: I52ea82e24336b496d996bbe3e445db0affe1abb8 --- libs/renderengine/Android.bp | 1 + libs/renderengine/ExternalTexture.cpp | 43 ++++ libs/renderengine/gl/GLESRenderEngine.cpp | 30 +-- libs/renderengine/gl/GLESRenderEngine.h | 11 +- .../include/renderengine/ExternalTexture.h | 61 ++++++ .../include/renderengine/LayerSettings.h | 8 +- .../include/renderengine/RenderEngine.h | 57 +++--- .../include/renderengine/mock/RenderEngine.h | 9 +- libs/renderengine/skia/AutoBackendTexture.h | 15 +- libs/renderengine/skia/Cache.cpp | 47 +++-- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 110 +++++----- libs/renderengine/skia/SkiaGLRenderEngine.h | 16 +- libs/renderengine/skia/SkiaRenderEngine.h | 10 +- libs/renderengine/tests/RenderEngineTest.cpp | 228 +++++++-------------- .../tests/RenderEngineThreadedTest.cpp | 9 +- .../renderengine/threaded/RenderEngineThreaded.cpp | 15 +- libs/renderengine/threaded/RenderEngineThreaded.h | 11 +- services/surfaceflinger/BufferLayer.cpp | 38 ++-- services/surfaceflinger/BufferLayer.h | 2 +- services/surfaceflinger/BufferLayerConsumer.cpp | 56 ++--- services/surfaceflinger/BufferLayerConsumer.h | 12 +- services/surfaceflinger/BufferStateLayer.cpp | 57 +++--- services/surfaceflinger/BufferStateLayer.h | 8 +- services/surfaceflinger/ClientCache.cpp | 13 +- services/surfaceflinger/ClientCache.h | 10 +- .../include/compositionengine/RenderSurface.h | 10 +- .../compositionengine/RenderSurfaceCreationArgs.h | 7 + .../impl/OutputLayerCompositionState.h | 4 +- .../include/compositionengine/impl/RenderSurface.h | 20 +- .../compositionengine/impl/planner/CachedSet.h | 30 +-- .../include/compositionengine/mock/RenderSurface.h | 2 +- .../CompositionEngine/src/Output.cpp | 31 +-- .../CompositionEngine/src/OutputLayer.cpp | 4 +- .../CompositionEngine/src/RenderSurface.cpp | 64 ++++-- .../CompositionEngine/src/planner/CachedSet.cpp | 14 +- .../CompositionEngine/src/planner/Planner.cpp | 7 +- .../CompositionEngine/tests/OutputLayerTest.cpp | 12 +- .../CompositionEngine/tests/OutputTest.cpp | 15 +- .../CompositionEngine/tests/RenderSurfaceTest.cpp | 46 +++-- .../tests/planner/CachedSetTest.cpp | 6 +- services/surfaceflinger/DisplayDevice.cpp | 12 +- services/surfaceflinger/Layer.cpp | 8 +- services/surfaceflinger/Layer.h | 13 +- services/surfaceflinger/RefreshRateOverlay.cpp | 15 +- services/surfaceflinger/RefreshRateOverlay.h | 11 +- services/surfaceflinger/RegionSamplingThread.cpp | 30 ++- services/surfaceflinger/RegionSamplingThread.h | 15 +- services/surfaceflinger/SurfaceFlinger.cpp | 69 +++---- services/surfaceflinger/SurfaceFlinger.h | 12 +- .../tests/unittests/CompositionTest.cpp | 33 +-- .../tests/unittests/TestableSurfaceFlinger.h | 4 +- .../tests/unittests/TransactionFrameTracerTest.cpp | 10 +- .../unittests/TransactionSurfaceFrameTest.cpp | 67 ++++-- 53 files changed, 804 insertions(+), 644 deletions(-) create mode 100644 libs/renderengine/ExternalTexture.cpp create mode 100644 libs/renderengine/include/renderengine/ExternalTexture.h (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index ec39137e24..f395ab43d8 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -48,6 +48,7 @@ filegroup { name: "librenderengine_sources", srcs: [ "Description.cpp", + "ExternalTexture.cpp", "Mesh.cpp", "RenderEngine.cpp", "Texture.cpp", diff --git a/libs/renderengine/ExternalTexture.cpp b/libs/renderengine/ExternalTexture.cpp new file mode 100644 index 0000000000..eabff58eba --- /dev/null +++ b/libs/renderengine/ExternalTexture.cpp @@ -0,0 +1,43 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "log/log_main.h" + +namespace android::renderengine { + +ExternalTexture::ExternalTexture(const sp& buffer, RenderEngine& renderEngine, + uint32_t usage) + : mBuffer(buffer), mRenderEngine(renderEngine) { + LOG_ALWAYS_FATAL_IF(buffer == nullptr, + "Attempted to bind a null buffer to an external texture!"); + // GLESRenderEngine has a separate texture cache for output buffers, + if (usage == Usage::WRITEABLE && + (mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::GLES || + mRenderEngine.getRenderEngineType() == RenderEngine::RenderEngineType::THREADED)) { + return; + } + mRenderEngine.mapExternalTextureBuffer(mBuffer, usage & Usage::WRITEABLE); +} + +ExternalTexture::~ExternalTexture() { + mRenderEngine.unmapExternalTextureBuffer(mBuffer); +} + +} // namespace android::renderengine diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index a2963a7c33..d87315fdc2 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -746,7 +746,8 @@ void GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, const sp& buffer) { +void GLESRenderEngine::mapExternalTextureBuffer(const sp& buffer, + bool /*isRenderable*/) { ATRACE_CALL(); mImageManager->cacheAsync(buffer, nullptr); } @@ -797,8 +798,8 @@ status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const spreleaseAsync(bufferId, nullptr); +void GLESRenderEngine::unmapExternalTextureBuffer(const sp& buffer) { + mImageManager->releaseAsync(buffer->getId(), nullptr); } std::shared_ptr GLESRenderEngine::unbindExternalTextureBufferForTesting( @@ -1102,7 +1103,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, + const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence, base::unique_fd* drawFence) { ATRACE_CALL(); @@ -1125,7 +1126,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, return BAD_VALUE; } - validateOutputBufferUsage(buffer); + validateOutputBufferUsage(buffer->getBuffer()); std::unique_ptr fbo; // Gathering layers that requested blur, we'll need them to decide when to render to an @@ -1142,11 +1143,13 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, if (blurLayersSize == 0) { fbo = std::make_unique(*this, - buffer.get()->getNativeBuffer(), + buffer->getBuffer() + .get() + ->getNativeBuffer(), useFramebufferCache); if (fbo->getStatus() != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors(); return fbo->getStatus(); } @@ -1157,7 +1160,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, mBlurFilter->setAsDrawTarget(display, blurLayers.front()->backgroundBlurRadius); if (status != NO_ERROR) { ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors(); return status; } @@ -1194,7 +1197,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, auto status = mBlurFilter->prepare(); if (status != NO_ERROR) { ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors("Can't render first blur pass"); return status; } @@ -1203,6 +1206,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, // Done blurring, time to bind the native FBO and render our blur onto it. fbo = std::make_unique(*this, buffer.get() + ->getBuffer() ->getNativeBuffer(), useFramebufferCache); status = fbo->getStatus(); @@ -1215,7 +1219,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, } if (status != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors("Can't bind native framebuffer"); return status; } @@ -1223,7 +1227,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, status = mBlurFilter->render(blurLayersSize > 1); if (status != NO_ERROR) { ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->handle); + buffer->getBuffer()->handle); checkErrors("Can't render blur filter"); return status; } @@ -1250,7 +1254,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, disableTexture = false; isOpaque = layer->source.buffer.isOpaque; - sp gBuf = layer->source.buffer.buffer; + sp gBuf = layer->source.buffer.buffer->getBuffer(); validateInputBufferUsage(gBuf); bindExternalTextureBuffer(layer->source.buffer.textureName, gBuf, layer->source.buffer.fence); @@ -1274,7 +1278,7 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, // Do not cache protected EGLImage, protected memory is limited. if (gBuf->getUsage() & GRALLOC_USAGE_PROTECTED) { - unbindExternalTextureBuffer(gBuf->getId()); + unmapExternalTextureBuffer(gBuf); } } diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index cd7a86bb0e..e7ed9c01fa 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -60,16 +60,14 @@ public: void primeCache() override; void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; - void cacheExternalTextureBuffer(const sp& buffer) EXCLUDES(mRenderingMutex); - void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex); - bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; bool useProtectedContext(bool useProtectedContext) override; status_t drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; + const std::shared_ptr& buffer, + const bool useFramebufferCache, base::unique_fd&& bufferFence, + base::unique_fd* drawFence) override; bool cleanupPostRender(CleanupMode mode) override; int getContextPriority() override; bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } @@ -105,6 +103,9 @@ protected: EXCLUDES(mFramebufferImageCacheMutex); size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; + void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) + EXCLUDES(mRenderingMutex); + void unmapExternalTextureBuffer(const sp& buffer) EXCLUDES(mRenderingMutex); private: friend class BindNativeBufferAsFramebuffer; diff --git a/libs/renderengine/include/renderengine/ExternalTexture.h b/libs/renderengine/include/renderengine/ExternalTexture.h new file mode 100644 index 0000000000..07f0833d4a --- /dev/null +++ b/libs/renderengine/include/renderengine/ExternalTexture.h @@ -0,0 +1,61 @@ +/* + * Copyright 2021 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 +#include + +namespace android::renderengine { + +class RenderEngine; + +/** + * Manages GPU image resources on behalf of clients using RenderEngine. + * + * Clients of RenderEngine are required to wrap their GraphicBuffer objects as an ExternalTexture, + * which is then mapped into GPU resources required by RenderEngine. When a client no longer needs + * to use the GraphicBuffer as input into RenderEngine::drawLayers, then the client should delete + * their ExternalTexture so that resources may be freed. + */ +class ExternalTexture { +public: + // Usage specifies the rendering intent for the buffer. + enum Usage : uint32_t { + // When a buffer is not READABLE but is WRITEABLE, then GLESRenderEngine will use that as a + // hint to load the buffer into a separate cache + READABLE = 1 << 0, + + // The buffer needs to be mapped as a 2D texture if set, otherwise must be mapped as an + // external texture + WRITEABLE = 1 << 1, + }; + // Creates an ExternalTexture for the provided buffer and RenderEngine instance, with the given + // usage hint of type Usage. + ExternalTexture(const sp& buffer, RenderEngine& renderEngine, uint32_t usage); + + ~ExternalTexture(); + + // Retrieves the buffer that is bound to this texture. + const sp& getBuffer() const { return mBuffer; } + +private: + sp mBuffer; + RenderEngine& mRenderEngine; + DISALLOW_COPY_AND_ASSIGN(ExternalTexture); +}; + +} // namespace android::renderengine diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index 7661233967..c54c5ba047 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -16,11 +16,9 @@ #pragma once -#include - #include #include -#include +#include #include #include #include @@ -31,6 +29,8 @@ #include #include +#include + namespace android { namespace renderengine { @@ -39,7 +39,7 @@ struct Buffer { // Buffer containing the image that we will render. // If buffer == nullptr, then the rest of the fields in this struct will be // ignored. - sp buffer = nullptr; + std::shared_ptr buffer = nullptr; // Fence that will fire when the buffer is ready to be bound. sp fence = nullptr; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 8dd98c3ba3..c8a0f0a034 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -17,19 +17,20 @@ #ifndef SF_RENDERENGINE_H_ #define SF_RENDERENGINE_H_ -#include -#include -#include - #include #include #include +#include #include #include #include +#include +#include #include #include +#include + /** * Allows to set RenderEngine backend to GLES (default) or SkiaGL (NOT yet supported). */ @@ -51,6 +52,7 @@ class Region; namespace renderengine { +class ExternalTexture; class Image; class Mesh; class Texture; @@ -104,23 +106,6 @@ public: virtual void genTextures(size_t count, uint32_t* names) = 0; virtual void deleteTextures(size_t count, uint32_t const* names) = 0; - // Caches Image resources for this buffer, but does not bind the buffer to - // a particular texture. - // Note that work is deferred to an additional thread, i.e. this call - // is made asynchronously, but the caller can expect that cache/unbind calls - // are performed in a manner that's conflict serializable, i.e. unbinding - // a buffer should never occur before binding the buffer if the caller - // called {bind, cache}ExternalTextureBuffer before calling unbind. - virtual void cacheExternalTextureBuffer(const sp& buffer) = 0; - // Removes internal resources referenced by the bufferId. This method should be - // invoked when the caller will no longer hold a reference to a GraphicBuffer - // and needs to clean up its resources. - // Note that work is deferred to an additional thread, i.e. this call - // is made asynchronously, but the caller can expect that cache/unbind calls - // are performed in a manner that's conflict serializable, i.e. unbinding - // a buffer should never occur before binding the buffer if the caller - // called {bind, cache}ExternalTextureBuffer before calling unbind. - virtual void unbindExternalTextureBuffer(uint64_t bufferId) = 0; enum class CleanupMode { CLEAN_OUTPUT_RESOURCES, @@ -191,8 +176,9 @@ public: // now, this always returns NO_ERROR. virtual status_t drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence, base::unique_fd* drawFence) = 0; + const std::shared_ptr& buffer, + const bool useFramebufferCache, base::unique_fd&& bufferFence, + base::unique_fd* drawFence) = 0; virtual void cleanFramebufferCache() = 0; // Returns the priority this context was actually created with. Note: this may not be // the same as specified at context creation time, due to implementation limits on the @@ -213,6 +199,31 @@ public: static void validateOutputBufferUsage(const sp&); protected: + // Maps GPU resources for this buffer. + // Note that work may be deferred to an additional thread, i.e. this call + // is made asynchronously, but the caller can expect that map/unmap calls + // are performed in a manner that's conflict serializable, i.e. unmapping + // a buffer should never occur before binding the buffer if the caller + // called mapExternalTextureBuffer before calling unmap. + // Note also that if the buffer contains protected content, then mapping those GPU resources may + // be deferred until the buffer is really used for drawing. This is because typical SoCs that + // support protected memory only support a limited amount, so optimisitically mapping protected + // memory may be too burdensome. If a buffer contains protected content and the RenderEngine + // implementation supports protected context, then GPU resources may be mapped into both the + // protected and unprotected contexts. + // If the buffer may ever be written to by RenderEngine, then isRenderable must be true. + virtual void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) = 0; + // Unmaps GPU resources used by this buffer. This method should be + // invoked when the caller will no longer hold a reference to a GraphicBuffer + // and needs to clean up its resources. + // Note that if there are multiple callers holding onto the same buffer, then the buffer's + // resources may be internally ref-counted to guard against use-after-free errors. Note that + // work may be deferred to an additional thread, i.e. this call is expected to be made + // asynchronously, but the caller can expect that map/unmap calls are performed in a manner + // that's conflict serializable, i.e. unmap a buffer should never occur before binding the + // buffer if the caller called mapExternalTextureBuffer before calling unmap. + virtual void unmapExternalTextureBuffer(const sp& buffer) = 0; + friend class ExternalTexture; friend class threaded::RenderEngineThreaded; const RenderEngineType mRenderEngineType; }; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index 228553d643..27dbd1ecf3 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -39,8 +39,6 @@ public: MOCK_METHOD1(dump, void(std::string&)); MOCK_METHOD2(genTextures, void(size_t, uint32_t*)); MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*)); - MOCK_METHOD1(cacheExternalTextureBuffer, void(const sp&)); - MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t)); MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&)); MOCK_CONST_METHOD0(getMaxTextureSize, size_t()); MOCK_CONST_METHOD0(getMaxViewportDims, size_t()); @@ -50,12 +48,17 @@ public: MOCK_METHOD1(cleanupPostRender, bool(CleanupMode mode)); MOCK_METHOD6(drawLayers, status_t(const DisplaySettings&, const std::vector&, - const sp&, const bool, base::unique_fd&&, + const std::shared_ptr&, const bool, base::unique_fd&&, base::unique_fd*)); MOCK_METHOD0(cleanFramebufferCache, void()); MOCK_METHOD0(getContextPriority, int()); MOCK_METHOD0(supportsBackgroundBlur, bool()); MOCK_METHOD1(onPrimaryDisplaySizeChanged, void(ui::Size)); + +protected: + // mock renderengine still needs to implement these, but callers should never need to call them. + void mapExternalTextureBuffer(const sp&, bool) {} + void unmapExternalTextureBuffer(const sp&) {} }; } // namespace mock diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h index bb758780e1..2d61cf854b 100644 --- a/libs/renderengine/skia/AutoBackendTexture.h +++ b/libs/renderengine/skia/AutoBackendTexture.h @@ -21,9 +21,9 @@ #include #include #include +#include #include "android-base/macros.h" -#include "ui/GraphicTypes.h" namespace android { namespace renderengine { @@ -41,13 +41,18 @@ public: // of shared ownership with Skia objects, so we wrap it here instead. class LocalRef { public: - LocalRef() {} + LocalRef(AutoBackendTexture* texture) { setTexture(texture); } ~LocalRef() { // Destroying the texture is the same as setting it to null setTexture(nullptr); } + AutoBackendTexture* getTexture() const { return mTexture; } + + DISALLOW_COPY_AND_ASSIGN(LocalRef); + + private: // Sets the texture to locally ref-track. void setTexture(AutoBackendTexture* texture) { if (mTexture != nullptr) { @@ -59,12 +64,6 @@ public: mTexture->ref(); } } - - AutoBackendTexture* getTexture() const { return mTexture; } - - DISALLOW_COPY_AND_ASSIGN(LocalRef); - - private: AutoBackendTexture* mTexture = nullptr; }; diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index 1db20c0be0..1c2b2fc3ca 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -46,7 +46,7 @@ constexpr auto kDestDataSpace = ui::Dataspace::SRGB; } // namespace static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - sp dstBuffer) { + const std::shared_ptr& dstTexture) { // Somewhat arbitrary dimensions, but on screen and slightly shorter, based // on actual use. FloatRect rect(0, 0, display.physicalDisplay.width(), display.physicalDisplay.height() - 30); @@ -73,7 +73,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin auto layers = std::vector{&layer}; // The identity matrix will generate the fast shader - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, base::unique_fd(), + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); // This matrix, which has different scales for x and y, will // generate the slower (more general case) version, which has variants for translucent @@ -86,13 +86,14 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin // clang-format on for (auto translucent : {false, true}) { layer.shadow.casterIsTranslucent = translucent; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); } } static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - sp dstBuffer, sp srcBuffer) { + const std::shared_ptr& dstTexture, + const std::shared_ptr& srcTexture) { const Rect& displayRect = display.physicalDisplay; FloatRect rect(0, 0, displayRect.width(), displayRect.height()); LayerSettings layer{ @@ -103,7 +104,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting }, .source = PixelSource{.buffer = Buffer{ - .buffer = srcBuffer, + .buffer = srcTexture, .maxMasteringLuminance = 1000.f, .maxContentLuminance = 1000.f, }}, @@ -126,7 +127,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting layer.source.buffer.isOpaque = isOpaque; for (auto alpha : {half(.23999f), half(1.0f)}) { layer.alpha = alpha; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); } } @@ -135,7 +136,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting } static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - sp dstBuffer) { + const std::shared_ptr& dstTexture) { const Rect& displayRect = display.physicalDisplay; FloatRect rect(0, 0, displayRect.width(), displayRect.height()); LayerSettings layer{ @@ -143,11 +144,11 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting Geometry{ .boundaries = rect, }, - .alpha = 1, .source = PixelSource{ .solidColor = half3(0.1f, 0.2f, 0.3f), }, + .alpha = 1, }; auto layers = std::vector{&layer}; @@ -155,14 +156,14 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting layer.geometry.positionTransform = transform; for (float roundedCornersRadius : {0.0f, 0.05f, 50.f}) { layer.geometry.roundedCornersRadius = roundedCornersRadius; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); } } } static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, - sp dstBuffer) { + const std::shared_ptr& dstTexture) { const Rect& displayRect = display.physicalDisplay; FloatRect rect(0, 0, displayRect.width(), displayRect.height()); LayerSettings layer{ @@ -176,7 +177,7 @@ static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings auto layers = std::vector{&layer}; for (int radius : {9, 60}) { layer.backgroundBlurRadius = radius; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(), nullptr); } } @@ -214,6 +215,9 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { sp dstBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usage, "primeShaderCache_dst"); + + const auto dstTexture = std::make_shared(dstBuffer, *renderengine, + ExternalTexture::Usage::WRITEABLE); // This buffer will be the source for the call to drawImageLayers. Draw // something to it as a placeholder for what an app draws. We should draw // something, but the details are not important. Make use of the shadow layer drawing step @@ -222,11 +226,16 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usage, "drawImageLayer_src"); - drawSolidLayers(renderengine, display, dstBuffer); - drawShadowLayers(renderengine, display, srcBuffer); - drawBlurLayers(renderengine, display, dstBuffer); + const auto srcTexture = + std::make_shared(srcBuffer, *renderengine, + ExternalTexture::Usage::READABLE | + ExternalTexture::Usage::WRITEABLE); + + drawSolidLayers(renderengine, display, dstTexture); + drawShadowLayers(renderengine, display, srcTexture); + drawBlurLayers(renderengine, display, dstTexture); // The majority of shaders are related to sampling images. - drawImageLayers(renderengine, display, dstBuffer, srcBuffer); + drawImageLayers(renderengine, display, dstTexture, srcTexture); // should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE; @@ -234,12 +243,12 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { sp externalBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usageExternal, "primeShaderCache_external"); + const auto externalTexture = + std::make_shared(externalBuffer, *renderengine, + ExternalTexture::Usage::READABLE); // TODO(b/184665179) doubles number of image shader compilations, but only somewhere // between 6 and 8 will occur in real uses. - drawImageLayers(renderengine, display, dstBuffer, externalBuffer); - renderengine->unbindExternalTextureBuffer(externalBuffer->getId()); - - renderengine->unbindExternalTextureBuffer(srcBuffer->getId()); + drawImageLayers(renderengine, display, dstTexture, externalTexture); const nsecs_t timeAfter = systemTime(); const float compileTimeMs = static_cast(timeAfter - timeBefore) / 1.0E6; diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index df40dd9c2d..37d98a3a8f 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -329,8 +329,6 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL } SkiaGLRenderEngine::~SkiaGLRenderEngine() { - cleanFramebufferCache(); - std::lock_guard lock(mRenderingMutex); if (mBlurFilter) { delete mBlurFilter; @@ -484,7 +482,8 @@ static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destin sourceTransfer != destTransfer; } -void SkiaGLRenderEngine::cacheExternalTextureBuffer(const sp& buffer) { +void SkiaGLRenderEngine::mapExternalTextureBuffer(const sp& buffer, + bool isRenderable) { // Only run this if RE is running on its own thread. This way the access to GL // operations is guaranteed to be happening on the same thread. if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED) { @@ -505,25 +504,41 @@ void SkiaGLRenderEngine::cacheExternalTextureBuffer(const sp& buf auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache; std::lock_guard lock(mRenderingMutex); - auto iter = cache.find(buffer->getId()); - if (iter != cache.end()) { - ALOGV("Texture already exists in cache."); - } else { + mGraphicBufferExternalRefs[buffer->getId()]++; + + if (const auto& iter = cache.find(buffer->getId()); iter == cache.end()) { std::shared_ptr imageTextureRef = - std::make_shared(); - imageTextureRef->setTexture( - new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), false)); + std::make_shared( + new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), + isRenderable)); cache.insert({buffer->getId(), imageTextureRef}); } // restore the original state of the protected context if necessary useProtectedContext(protectedContextState); } -void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { +void SkiaGLRenderEngine::unmapExternalTextureBuffer(const sp& buffer) { ATRACE_CALL(); std::lock_guard lock(mRenderingMutex); - mTextureCache.erase(bufferId); - mProtectedTextureCache.erase(bufferId); + if (const auto& iter = mGraphicBufferExternalRefs.find(buffer->getId()); + iter != mGraphicBufferExternalRefs.end()) { + if (iter->second == 0) { + ALOGW("Attempted to unmap GraphicBuffer from RenderEngine texture, but the " + "ref count was already zero!", + buffer->getId()); + mGraphicBufferExternalRefs.erase(buffer->getId()); + return; + } + + iter->second--; + + if (iter->second == 0) { + mTextureCache.erase(buffer->getId()); + mProtectedTextureCache.erase(buffer->getId()); + mGraphicBufferExternalRefs.erase(buffer->getId()); + } + } } sk_sp SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp shader, @@ -621,8 +636,8 @@ private: status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, - const bool useFramebufferCache, + const std::shared_ptr& buffer, + const bool /*useFramebufferCache*/, base::unique_fd&& bufferFence, base::unique_fd* drawFence) { ATRACE_NAME("SkiaGL::drawLayers"); @@ -645,32 +660,18 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, return BAD_VALUE; } - validateOutputBufferUsage(buffer); + validateOutputBufferUsage(buffer->getBuffer()); auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext; auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache; - AHardwareBuffer_Desc bufferDesc; - AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc); - - std::shared_ptr surfaceTextureRef = nullptr; - if (useFramebufferCache) { - auto iter = cache.find(buffer->getId()); - if (iter != cache.end()) { - ALOGV("Cache hit!"); - ATRACE_NAME("Cache hit"); - surfaceTextureRef = iter->second; - } - } - if (surfaceTextureRef == nullptr || surfaceTextureRef->getTexture() == nullptr) { - ATRACE_NAME("Cache miss"); - surfaceTextureRef = std::make_shared(); - surfaceTextureRef->setTexture( - new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), true)); - if (useFramebufferCache) { - ALOGD("Adding to cache"); - cache.insert({buffer->getId(), surfaceTextureRef}); - } + std::shared_ptr surfaceTextureRef; + if (const auto& it = cache.find(buffer->getBuffer()->getId()); it != cache.end()) { + surfaceTextureRef = it->second; + } else { + surfaceTextureRef = std::make_shared( + new AutoBackendTexture(grContext.get(), buffer->getBuffer()->toAHardwareBuffer(), + true)); } const ui::Dataspace dstDataspace = @@ -876,18 +877,22 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, SkPaint paint; if (layer->source.buffer.buffer) { ATRACE_NAME("DrawImage"); - validateInputBufferUsage(layer->source.buffer.buffer); + validateInputBufferUsage(layer->source.buffer.buffer->getBuffer()); const auto& item = layer->source.buffer; std::shared_ptr imageTextureRef = nullptr; - auto iter = cache.find(item.buffer->getId()); - if (iter != cache.end()) { + + if (const auto& iter = cache.find(item.buffer->getBuffer()->getId()); + iter != cache.end()) { imageTextureRef = iter->second; } else { - imageTextureRef = std::make_shared(); - imageTextureRef->setTexture(new AutoBackendTexture(grContext.get(), - item.buffer->toAHardwareBuffer(), - false)); - cache.insert({item.buffer->getId(), imageTextureRef}); + // If we didn't find the image in the cache, then create a local ref but don't cache + // it. If we're using skia, we're guaranteed to run on a dedicated GPU thread so if + // we didn't find anything in the cache then we intentionally did not cache this + // buffer's resources. + imageTextureRef = std::make_shared( + new AutoBackendTexture(grContext.get(), + item.buffer->getBuffer()->toAHardwareBuffer(), + false)); } sk_sp image = @@ -1200,15 +1205,6 @@ EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay dis return eglCreatePbufferSurface(display, placeholderConfig, attributes.data()); } -void SkiaGLRenderEngine::cleanFramebufferCache() { - // TODO(b/180767535) Remove this method and use b/180767535 instead, which would allow - // SF to control texture lifecycle more tightly rather than through custom hooks into RE. - std::lock_guard lock(mRenderingMutex); - mRuntimeEffects.clear(); - mProtectedTextureCache.clear(); - mTextureCache.clear(); -} - int SkiaGLRenderEngine::getContextPriority() { int value; eglQueryContext(mEGLDisplay, mEGLContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &value); @@ -1281,6 +1277,12 @@ void SkiaGLRenderEngine::dump(std::string& result) { StringAppendF(&result, "Skia's Wrapped Objects:\n"); gpuReporter.logOutput(result, true); + StringAppendF(&result, "RenderEngine tracked buffers: %zu\n", + mGraphicBufferExternalRefs.size()); + StringAppendF(&result, "Dumping buffer ids...\n"); + for (const auto& [id, refCounts] : mGraphicBufferExternalRefs) { + StringAppendF(&result, "- 0x%" PRIx64 " - %d refs \n", id, refCounts); + } StringAppendF(&result, "RenderEngine AHB/BackendTexture cache size: %zu\n", mTextureCache.size()); StringAppendF(&result, "Dumping buffer ids...\n"); diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 8e77c16b40..e71c560a1f 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -52,13 +53,12 @@ public: ~SkiaGLRenderEngine() override EXCLUDES(mRenderingMutex); void primeCache() override; - void cacheExternalTextureBuffer(const sp& buffer) override; - void unbindExternalTextureBuffer(uint64_t bufferId) override; status_t drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; - void cleanFramebufferCache() override; + const std::shared_ptr& buffer, + const bool useFramebufferCache, base::unique_fd&& bufferFence, + base::unique_fd* drawFence) override; + void cleanFramebufferCache() override {} int getContextPriority() override; bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; @@ -72,6 +72,8 @@ protected: void dump(std::string& result) override; size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; + void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) override; + void unmapExternalTextureBuffer(const sp& buffer) override; private: static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); @@ -114,7 +116,9 @@ private: const PixelFormat mDefaultPixelFormat; const bool mUseColorManagement; - // Cache of GL textures that we'll store per GraphicBuffer ID + // Number of external holders of ExternalTexture references, per GraphicBuffer ID. + std::unordered_map mGraphicBufferExternalRefs GUARDED_BY(mRenderingMutex); + // Cache of GL textures that we'll store per GraphicBuffer ID, sliced by GPU context. std::unordered_map> mTextureCache GUARDED_BY(mRenderingMutex); std::unordered_map> diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 51ef088a25..308c5ffa9f 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -42,15 +42,12 @@ public: virtual void primeCache() override{}; virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override{}; virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{}; - virtual void cacheExternalTextureBuffer(const sp& /*buffer*/){}; - virtual void unbindExternalTextureBuffer(uint64_t /*bufferId*/){}; - virtual bool isProtected() const override { return false; } // mInProtectedContext; } virtual bool supportsProtectedContent() const override { return false; }; virtual bool useProtectedContext(bool /*useProtectedContext*/) override { return false; }; virtual status_t drawLayers(const DisplaySettings& /*display*/, const std::vector& /*layers*/, - const sp& /*buffer*/, + const std::shared_ptr& /*buffer*/, const bool /*useFramebufferCache*/, base::unique_fd&& /*bufferFence*/, base::unique_fd* /*drawFence*/) override { @@ -60,6 +57,11 @@ public: virtual int getContextPriority() override { return 0; } virtual void assertShadersCompiled(int numShaders) {} virtual int reportShadersCompiled() { return 0; } + +protected: + virtual void mapExternalTextureBuffer(const sp& /*buffer*/, + bool /*isRenderable*/) override; + virtual void unmapExternalTextureBuffer(const sp& /*buffer*/) override; }; } // namespace skia diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 7846156383..d63c88bc02 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -160,27 +161,42 @@ public: class RenderEngineTest : public ::testing::TestWithParam> { public: - static sp allocateDefaultBuffer() { - return new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, - "output"); + std::shared_ptr allocateDefaultBuffer() { + return std::make_shared< + renderengine:: + ExternalTexture>(new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, + DEFAULT_DISPLAY_HEIGHT, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE, + "output"), + *mRE, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); } // Allocates a 1x1 buffer to fill with a solid color - static sp allocateSourceBuffer(uint32_t width, uint32_t height) { - return new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_TEXTURE, - "input"); + std::shared_ptr allocateSourceBuffer(uint32_t width, + uint32_t height) { + return std::make_shared< + renderengine:: + ExternalTexture>(new GraphicBuffer(width, height, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN | + GRALLOC_USAGE_HW_TEXTURE, + "input"), + *mRE, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); } RenderEngineTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - mBuffer = allocateDefaultBuffer(); } ~RenderEngineTest() { @@ -211,20 +227,21 @@ public: } uint8_t* pixels; - mBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + mBuffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); file << "P6\n"; - file << mBuffer->getWidth() << "\n"; - file << mBuffer->getHeight() << "\n"; + file << mBuffer->getBuffer()->getWidth() << "\n"; + file << mBuffer->getBuffer()->getHeight() << "\n"; file << 255 << "\n"; - std::vector outBuffer(mBuffer->getWidth() * mBuffer->getHeight() * 3); + std::vector outBuffer(mBuffer->getBuffer()->getWidth() * + mBuffer->getBuffer()->getHeight() * 3); auto outPtr = reinterpret_cast(outBuffer.data()); - for (int32_t j = 0; j < mBuffer->getHeight(); j++) { - const uint8_t* src = pixels + (mBuffer->getStride() * j) * 4; - for (int32_t i = 0; i < mBuffer->getWidth(); i++) { + for (int32_t j = 0; j < mBuffer->getBuffer()->getHeight(); j++) { + const uint8_t* src = pixels + (mBuffer->getBuffer()->getStride() * j) * 4; + for (int32_t i = 0; i < mBuffer->getBuffer()->getWidth(); i++) { // Only copy R, G and B components outPtr[0] = src[0]; outPtr[1] = src[1]; @@ -235,7 +252,7 @@ public: } } file.write(reinterpret_cast(outBuffer.data()), outBuffer.size()); - mBuffer->unlock(); + mBuffer->getBuffer()->unlock(); } void expectBufferColor(const Region& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { @@ -262,13 +279,13 @@ public: void expectBufferColor(const Rect& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a, std::function colorCompare) { uint8_t* pixels; - mBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + mBuffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); int32_t maxFails = 10; int32_t fails = 0; for (int32_t j = 0; j < region.getHeight(); j++) { - const uint8_t* src = - pixels + (mBuffer->getStride() * (region.top + j) + region.left) * 4; + const uint8_t* src = pixels + + (mBuffer->getBuffer()->getStride() * (region.top + j) + region.left) * 4; for (int32_t i = 0; i < region.getWidth(); i++) { const uint8_t expected[4] = {r, g, b, a}; bool equal = colorCompare(src, expected); @@ -289,7 +306,7 @@ public: break; } } - mBuffer->unlock(); + mBuffer->getBuffer()->unlock(); } void expectAlpha(const Rect& rect, uint8_t a) { @@ -387,7 +404,6 @@ public: base::unique_fd fence; status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fence); - mCurrentBuffer = mBuffer; int fd = fence.release(); if (fd >= 0) { @@ -397,7 +413,7 @@ public: ASSERT_EQ(NO_ERROR, status); if (layers.size() > 0 && mGLESRE != nullptr) { - ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId())); + ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId())); } } @@ -503,17 +519,11 @@ public: void initializeRenderEngine(); std::unique_ptr mRE; + std::shared_ptr mBuffer; // GLESRenderEngine for testing GLES-specific behavior. // Owened by mRE, but this is downcasted. renderengine::gl::GLESRenderEngine* mGLESRE = nullptr; - // Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to - // be freed *after* RenderEngine is destroyed, so that the EGL image is - // destroyed first. - sp mCurrentBuffer; - - sp mBuffer; - std::vector mTexNames; }; @@ -530,6 +540,7 @@ void RenderEngineTest::initializeRenderEngine() { } else { mRE = renderEngineFactory->createRenderEngine(); } + mBuffer = allocateDefaultBuffer(); } struct ColorSourceVariant { @@ -566,18 +577,18 @@ template struct BufferSourceVariant { static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b, RenderEngineTest* fixture) { - sp buf = RenderEngineTest::allocateSourceBuffer(1, 1); + const auto buf = fixture->allocateSourceBuffer(1, 1); uint32_t texName; fixture->mRE->genTextures(1, &texName); fixture->mTexNames.push_back(texName); uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); - for (int32_t j = 0; j < buf->getHeight(); j++) { - uint8_t* iter = pixels + (buf->getStride() * j) * 4; - for (int32_t i = 0; i < buf->getWidth(); i++) { + for (int32_t j = 0; j < buf->getBuffer()->getHeight(); j++) { + uint8_t* iter = pixels + (buf->getBuffer()->getStride() * j) * 4; + for (int32_t i = 0; i < buf->getBuffer()->getWidth(); i++) { iter[0] = uint8_t(r * 255); iter[1] = uint8_t(g * 255); iter[2] = uint8_t(b * 255); @@ -586,7 +597,7 @@ struct BufferSourceVariant { } } - buf->unlock(); + buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1012,14 +1023,14 @@ void RenderEngineTest::fillRedBufferTextureTransform() { layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; // Here will allocate a checker board texture, but transform texture // coordinates so that only the upper left is applied. - sp buf = allocateSourceBuffer(2, 2); + const auto buf = allocateSourceBuffer(2, 2); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); // Red top left, Green top right, Blue bottom left, Black bottom right pixels[0] = 255; pixels[1] = 0; @@ -1033,7 +1044,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() { pixels[9] = 0; pixels[10] = 255; pixels[11] = 255; - buf->unlock(); + buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1061,19 +1072,19 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() { std::vector layers; renderengine::LayerSettings layer; - sp buf = allocateSourceBuffer(1, 1); + const auto buf = allocateSourceBuffer(1, 1); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); pixels[0] = 255; pixels[1] = 0; pixels[2] = 0; pixels[3] = 255; - buf->unlock(); + buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1100,19 +1111,19 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() { std::vector layers; renderengine::LayerSettings layer; - sp buf = allocateSourceBuffer(1, 1); + const auto buf = allocateSourceBuffer(1, 1); uint32_t texName; RenderEngineTest::mRE->genTextures(1, &texName); this->mTexNames.push_back(texName); uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); pixels[0] = 255; pixels[1] = 0; pixels[2] = 0; pixels[3] = 255; - buf->unlock(); + buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; layer.source.buffer.textureName = texName; @@ -1233,8 +1244,7 @@ TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) { } TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) { - const auto& renderEngineFactory = GetParam(); - mRE = renderEngineFactory->createRenderEngine(); + initializeRenderEngine(); renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1295,7 +1305,6 @@ TEST_P(RenderEngineTest, drawLayers_nullOutputFence) { layers.push_back(&layer); status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), nullptr); - mCurrentBuffer = mBuffer; ASSERT_EQ(NO_ERROR, status); expectBufferColor(fullscreenRect(), 255, 0, 0, 255); } @@ -1323,9 +1332,8 @@ TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) { layers.push_back(&layer); status_t status = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd(), nullptr); - mCurrentBuffer = mBuffer; ASSERT_EQ(NO_ERROR, status); - ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId())); + ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId())); expectBufferColor(fullscreenRect(), 255, 0, 0, 255); } @@ -1574,98 +1582,6 @@ TEST_P(RenderEngineTest, drawLayers_clearRegion) { clearRegion(); } -TEST_P(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) { - const auto& renderEngineFactory = GetParam(); - - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - // GLES-specific test - return; - } - - initializeRenderEngine(); - - renderengine::DisplaySettings settings; - settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - settings.physicalDisplay = fullscreenRect(); - settings.clip = fullscreenRect(); - - std::vector layers; - - renderengine::LayerSettings layer; - layer.geometry.boundaries = fullscreenRect().toFloatRect(); - BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); - - layers.push_back(&layer); - invokeDraw(settings, layers); - uint64_t bufferId = layer.source.buffer.buffer->getId(); - EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId)); - std::shared_ptr barrier = - mGLESRE->unbindExternalTextureBufferForTesting(bufferId); - std::lock_guard lock(barrier->mutex); - ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), - [&]() REQUIRES(barrier->mutex) { - return barrier->isOpen; - })); - EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId)); - EXPECT_EQ(NO_ERROR, barrier->result); -} - -TEST_P(RenderEngineTest, cacheExternalBuffer_withNullBuffer) { - const auto& renderEngineFactory = GetParam(); - - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - // GLES-specific test - return; - } - - initializeRenderEngine(); - - std::shared_ptr barrier = - mGLESRE->cacheExternalTextureBufferForTesting(nullptr); - std::lock_guard lock(barrier->mutex); - ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), - [&]() REQUIRES(barrier->mutex) { - return barrier->isOpen; - })); - EXPECT_TRUE(barrier->isOpen); - EXPECT_EQ(BAD_VALUE, barrier->result); -} - -TEST_P(RenderEngineTest, cacheExternalBuffer_cachesImages) { - const auto& renderEngineFactory = GetParam(); - - if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) { - // GLES-specific test - return; - } - - initializeRenderEngine(); - - sp buf = allocateSourceBuffer(1, 1); - uint64_t bufferId = buf->getId(); - std::shared_ptr barrier = - mGLESRE->cacheExternalTextureBufferForTesting(buf); - { - std::lock_guard lock(barrier->mutex); - ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), - [&]() REQUIRES(barrier->mutex) { - return barrier->isOpen; - })); - EXPECT_EQ(NO_ERROR, barrier->result); - } - EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId)); - barrier = mGLESRE->unbindExternalTextureBufferForTesting(bufferId); - { - std::lock_guard lock(barrier->mutex); - ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), - [&]() REQUIRES(barrier->mutex) { - return barrier->isOpen; - })); - EXPECT_EQ(NO_ERROR, barrier->result); - } - EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId)); -} - TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) { initializeRenderEngine(); @@ -1858,7 +1774,7 @@ TEST_P(RenderEngineTest, cleanupPostRender_whenCleaningAll_replacesTextureMemory sync_wait(fd, -1); } - uint64_t bufferId = layer.source.buffer.buffer->getId(); + uint64_t bufferId = layer.source.buffer.buffer->getBuffer()->getId(); uint32_t texName = layer.source.buffer.textureName; EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId)); EXPECT_EQ(bufferId, mGLESRE->getBufferIdForTextureNameForTesting(texName)); @@ -1966,16 +1882,16 @@ TEST_P(RenderEngineTest, testDisableBlendingBuffer) { // The next layer will overwrite redLayer with a GraphicBuffer that is green // applied with a translucent alpha. - auto buf = allocateSourceBuffer(1, 1); + const auto buf = allocateSourceBuffer(1, 1); { uint8_t* pixels; - buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - reinterpret_cast(&pixels)); + buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); pixels[0] = 0; pixels[1] = 255; pixels[2] = 0; pixels[3] = 255; - buf->unlock(); + buf->getBuffer()->unlock(); } const renderengine::LayerSettings greenLayer{ diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index b093e88d4f..e3917cce09 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -162,15 +162,18 @@ TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsTrue) { TEST_F(RenderEngineThreadedTest, drawLayers) { renderengine::DisplaySettings settings; std::vector layers; - sp buffer = new GraphicBuffer(); + std::shared_ptr buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), *mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); base::unique_fd bufferFence; base::unique_fd drawFence; EXPECT_CALL(*mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings&, const std::vector&, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { return NO_ERROR; }); + const std::shared_ptr&, const bool, + base::unique_fd&&, base::unique_fd*) -> status_t { return NO_ERROR; }); status_t result = mThreadedRE->drawLayers(settings, layers, buffer, false, std::move(bufferFence), &drawFence); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index 190662be16..c87a836de1 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -160,27 +160,28 @@ void RenderEngineThreaded::deleteTextures(size_t count, uint32_t const* names) { resultFuture.wait(); } -void RenderEngineThreaded::cacheExternalTextureBuffer(const sp& buffer) { +void RenderEngineThreaded::mapExternalTextureBuffer(const sp& buffer, + bool isRenderable) { // This function is designed so it can run asynchronously, so we do not need to wait // for the futures. { std::lock_guard lock(mThreadMutex); mFunctionCalls.push([=](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::cacheExternalTextureBuffer"); - instance.cacheExternalTextureBuffer(buffer); + ATRACE_NAME("REThreaded::mapExternalTextureBuffer"); + instance.mapExternalTextureBuffer(buffer, isRenderable); }); } mCondition.notify_one(); } -void RenderEngineThreaded::unbindExternalTextureBuffer(uint64_t bufferId) { +void RenderEngineThreaded::unmapExternalTextureBuffer(const sp& buffer) { // This function is designed so it can run asynchronously, so we do not need to wait // for the futures. { std::lock_guard lock(mThreadMutex); mFunctionCalls.push([=](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::unbindExternalTextureBuffer"); - instance.unbindExternalTextureBuffer(bufferId); + ATRACE_NAME("REThreaded::unmapExternalTextureBuffer"); + instance.unmapExternalTextureBuffer(buffer); }); } mCondition.notify_one(); @@ -242,7 +243,7 @@ bool RenderEngineThreaded::cleanupPostRender(CleanupMode mode) { status_t RenderEngineThreaded::drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, + const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence, base::unique_fd* drawFence) { diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 61ae9b8cf8..eb6098ed8d 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -48,8 +48,6 @@ public: void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; - void cacheExternalTextureBuffer(const sp& buffer) override; - void unbindExternalTextureBuffer(uint64_t bufferId) override; size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; @@ -60,14 +58,19 @@ public: status_t drawLayers(const DisplaySettings& display, const std::vector& layers, - const sp& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; + const std::shared_ptr& buffer, + const bool useFramebufferCache, base::unique_fd&& bufferFence, + base::unique_fd* drawFence) override; void cleanFramebufferCache() override; int getContextPriority() override; bool supportsBackgroundBlur() override; void onPrimaryDisplaySizeChanged(ui::Size size) override; +protected: + void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) override; + void unmapExternalTextureBuffer(const sp& buffer) override; + private: void threadMain(CreateInstanceFactory factory); void waitUntilInitialized() const; diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 12f63dbbf1..d243989a34 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -188,7 +188,7 @@ std::optional BufferLayer::prepareCli const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || (isSecure() && !targetSettings.isSecure); const bool bufferCanBeUsedAsHwTexture = - mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; + mBufferInfo.mBuffer->getBuffer()->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; compositionengine::LayerFE::LayerSettings& layer = *result; if (blackOutLayer || !bufferCanBeUsedAsHwTexture) { ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable", @@ -213,7 +213,7 @@ std::optional BufferLayer::prepareCli ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel : defaultMaxContentLuminance; layer.frameNumber = mCurrentFrameNumber; - layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0; + layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer()->getId() : 0; const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering(); @@ -314,7 +314,7 @@ void BufferLayer::preparePerFrameCompositionState() { : Hwc2::IComposerClient::Composition::DEVICE; } - compositionState->buffer = mBufferInfo.mBuffer; + compositionState->buffer = mBufferInfo.mBuffer->getBuffer(); compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mBufferInfo.mBufferSlot; @@ -442,7 +442,7 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, void BufferLayer::gatherBufferInfo() { mBufferInfo.mPixelFormat = - !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->format; + !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getBuffer()->format; mBufferInfo.mFrameLatencyNeeded = true; } @@ -539,10 +539,10 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, } if (oldBufferInfo.mBuffer != nullptr) { - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); - if (bufWidth != uint32_t(oldBufferInfo.mBuffer->width) || - bufHeight != uint32_t(oldBufferInfo.mBuffer->height)) { + uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); + if (bufWidth != uint32_t(oldBufferInfo.mBuffer->getBuffer()->width) || + bufHeight != uint32_t(oldBufferInfo.mBuffer->getBuffer()->height)) { recomputeVisibleRegions = true; } } @@ -563,8 +563,8 @@ uint32_t BufferLayer::getEffectiveScalingMode() const { } bool BufferLayer::isProtected() const { - const sp& buffer(mBufferInfo.mBuffer); - return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED); + return (mBufferInfo.mBuffer != nullptr) && + (mBufferInfo.mBuffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED); } // As documented in libhardware header, formats in the range @@ -651,8 +651,8 @@ Rect BufferLayer::getBufferSize(const State& s) const { return Rect::INVALID_RECT; } - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); + uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { @@ -683,8 +683,8 @@ FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const return parentBounds; } - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); + uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight(); // Undo any transformations on the buffer and return the result. if (mBufferInfo.mTransform & ui::Transform::ROT_90) { @@ -726,7 +726,7 @@ Rect BufferLayer::getBufferCrop() const { return mBufferInfo.mCrop; } else if (mBufferInfo.mBuffer != nullptr) { // otherwise we use the whole buffer - return mBufferInfo.mBuffer->getBounds(); + return mBufferInfo.mBuffer->getBuffer()->getBounds(); } else { // if we don't have a buffer yet, we use an empty/invalid crop return Rect(); @@ -771,12 +771,14 @@ ui::Dataspace BufferLayer::translateDataspace(ui::Dataspace dataspace) { } sp BufferLayer::getBuffer() const { - return mBufferInfo.mBuffer; + return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr; } void BufferLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) { - GLConsumer::computeTransformMatrix(outMatrix, mBufferInfo.mBuffer, mBufferInfo.mCrop, - mBufferInfo.mTransform, filteringEnabled); + GLConsumer::computeTransformMatrix(outMatrix, + mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() + : nullptr, + mBufferInfo.mCrop, mBufferInfo.mTransform, filteringEnabled); } void BufferLayer::setInitialValuesForClone(const sp& clonedFrom) { diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 0a5235aa08..cd3d80e809 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -132,7 +132,7 @@ protected: PixelFormat mPixelFormat{PIXEL_FORMAT_NONE}; bool mTransformToDisplayInverse{false}; - sp mBuffer; + std::shared_ptr mBuffer; int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT}; bool mFrameLatencyNeeded{false}; diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 69d2d11a4d..96b22478ab 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -167,7 +166,7 @@ void BufferLayerConsumer::setReleaseFence(const sp& fence) { } auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer - : mCurrentTextureBuffer->graphicBuffer(); + : mCurrentTextureBuffer->getBuffer(); auto err = addReleaseFence(slot, buffer, fence); if (err != OK) { BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); @@ -206,9 +205,11 @@ status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t pres // before, so we need to clean up old references. if (item->mGraphicBuffer != nullptr) { std::lock_guard lock(mImagesMutex); - if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->graphicBuffer() == nullptr || - mImages[item->mSlot]->graphicBuffer()->getId() != item->mGraphicBuffer->getId()) { - mImages[item->mSlot] = std::make_shared(item->mGraphicBuffer, mRE); + if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->getBuffer() == nullptr || + mImages[item->mSlot]->getBuffer()->getId() != item->mGraphicBuffer->getId()) { + mImages[item->mSlot] = std::make_shared< + renderengine::ExternalTexture>(item->mGraphicBuffer, mRE, + renderengine::ExternalTexture::Usage::READABLE); } } @@ -222,8 +223,8 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, int slot = item.mSlot; BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, - (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->graphicBuffer() != nullptr) - ? mCurrentTextureBuffer->graphicBuffer()->handle + (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->getBuffer() != nullptr) + ? mCurrentTextureBuffer->getBuffer()->handle : 0, slot, mSlots[slot].mGraphicBuffer->handle); @@ -231,7 +232,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, // releaseBufferLocked() if we're in shared buffer mode and both buffers are // the same. - std::shared_ptr nextTextureBuffer; + std::shared_ptr nextTextureBuffer; { std::lock_guard lock(mImagesMutex); nextTextureBuffer = mImages[slot]; @@ -241,7 +242,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (pendingRelease == nullptr) { status_t status = - releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->graphicBuffer()); + releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->getBuffer()); if (status < NO_ERROR) { BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), status); @@ -250,7 +251,7 @@ status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, } } else { pendingRelease->currentTexture = mCurrentTexture; - pendingRelease->graphicBuffer = mCurrentTextureBuffer->graphicBuffer(); + pendingRelease->graphicBuffer = mCurrentTextureBuffer->getBuffer(); pendingRelease->isPending = true; } } @@ -301,14 +302,14 @@ void BufferLayerConsumer::setFilteringEnabled(bool enabled) { void BufferLayerConsumer::computeCurrentTransformMatrixLocked() { BLC_LOGV("computeCurrentTransformMatrixLocked"); - if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->graphicBuffer() == nullptr) { + if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->getBuffer() == nullptr) { BLC_LOGD("computeCurrentTransformMatrixLocked: " "mCurrentTextureBuffer is nullptr"); } GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, mCurrentTextureBuffer == nullptr ? nullptr - : mCurrentTextureBuffer->graphicBuffer(), + : mCurrentTextureBuffer->getBuffer(), getCurrentCropLocked(), mCurrentTransform, mFilteringEnabled); } @@ -360,7 +361,8 @@ int BufferLayerConsumer::getCurrentApi() const { return mCurrentApi; } -sp BufferLayerConsumer::getCurrentBuffer(int* outSlot, sp* outFence) const { +std::shared_ptr BufferLayerConsumer::getCurrentBuffer( + int* outSlot, sp* outFence) const { Mutex::Autolock lock(mMutex); if (outSlot != nullptr) { @@ -371,7 +373,7 @@ sp BufferLayerConsumer::getCurrentBuffer(int* outSlot, sp* *outFence = mCurrentFence; } - return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer->graphicBuffer(); + return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer; } Rect BufferLayerConsumer::getCurrentCrop() const { @@ -456,10 +458,12 @@ void BufferLayerConsumer::onSidebandStreamChanged() { void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) { if (item.mGraphicBuffer != nullptr && item.mSlot != BufferQueue::INVALID_BUFFER_SLOT) { std::lock_guard lock(mImagesMutex); - const std::shared_ptr& oldImage = mImages[item.mSlot]; - if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr || - oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) { - mImages[item.mSlot] = std::make_shared(item.mGraphicBuffer, mRE); + const std::shared_ptr& oldImage = mImages[item.mSlot]; + if (oldImage == nullptr || oldImage->getBuffer() == nullptr || + oldImage->getBuffer()->getId() != item.mGraphicBuffer->getId()) { + mImages[item.mSlot] = std::make_shared< + renderengine::ExternalTexture>(item.mGraphicBuffer, mRE, + renderengine::ExternalTexture::Usage::READABLE); } } } @@ -499,22 +503,6 @@ void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const ConsumerBase::dumpLocked(result, prefix); } - -BufferLayerConsumer::Image::Image(const sp& graphicBuffer, - renderengine::RenderEngine& engine) - : mGraphicBuffer(graphicBuffer), mRE(engine) { - if (graphicBuffer != nullptr && (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED)) { - return; - } - mRE.cacheExternalTextureBuffer(mGraphicBuffer); -} - -BufferLayerConsumer::Image::~Image() { - if (mGraphicBuffer != nullptr) { - ALOGV("Destroying buffer: %" PRId64, mGraphicBuffer->getId()); - mRE.unbindExternalTextureBuffer(mGraphicBuffer->getId()); - } -} }; // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index dd39214aff..9ed80b46bd 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -21,12 +21,11 @@ #include #include #include - +#include #include #include #include #include - #include #include #include @@ -39,7 +38,6 @@ class String8; namespace renderengine { class RenderEngine; -class Image; } // namespace renderengine /* @@ -153,7 +151,8 @@ public: // When outSlot is not nullptr, the current buffer slot index is also // returned. Simiarly, when outFence is not nullptr, the current output // fence is returned. - sp getCurrentBuffer(int* outSlot = nullptr, sp* outFence = nullptr) const; + std::shared_ptr getCurrentBuffer( + int* outSlot = nullptr, sp* outFence = nullptr) const; // getCurrentCrop returns the cropping rectangle of the current buffer. Rect getCurrentCrop() const; @@ -258,7 +257,7 @@ private: // mCurrentTextureBuffer is the buffer containing the current texture. It's // possible that this buffer is not associated with any buffer slot, so we // must track it separately in order to support the getCurrentBuffer method. - std::shared_ptr mCurrentTextureBuffer; + std::shared_ptr mCurrentTextureBuffer; // mCurrentCrop is the crop rectangle that applies to the current texture. // It gets set each time updateTexImage is called. @@ -337,7 +336,8 @@ private: int mCurrentTexture; // Shadow buffer cache for cleaning up renderengine references. - std::shared_ptr mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex); + std::shared_ptr + mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex); // Separate mutex guarding the shadow buffer cache. // mImagesMutex can be manipulated with binder threads (e.g. onBuffersAllocated) diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index fa9cecf787..ac2edbe717 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -71,14 +71,8 @@ BufferStateLayer::~BufferStateLayer() { // original layer and the clone should be removed at the same time so there shouldn't be any // issue with the clone layer trying to use the texture. if (mBufferInfo.mBuffer != nullptr && !isClone()) { - // Ensure that mBuffer is uncached from RenderEngine here, as - // RenderEngine may have been using the buffer as an external texture - // after the client uncached the buffer. - auto& engine(mFlinger->getRenderEngine()); - const uint64_t bufferId = mBufferInfo.mBuffer->getId(); - engine.unbindExternalTextureBuffer(bufferId); - callReleaseBufferCallback(mDrawingState.releaseBufferListener, mBufferInfo.mBuffer, - mBufferInfo.mFence); + callReleaseBufferCallback(mDrawingState.releaseBufferListener, + mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFence); } } @@ -344,8 +338,9 @@ bool BufferStateLayer::addFrameEvent(const sp& acquireFence, nsecs_t post return true; } -bool BufferStateLayer::setBuffer(const sp& buffer, const sp& acquireFence, - nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, +bool BufferStateLayer::setBuffer(const std::shared_ptr& buffer, + const sp& acquireFence, nsecs_t postTime, + nsecs_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, std::optional dequeueTime, const FrameTimelineInfo& info, const sp& releaseBufferListener) { @@ -353,12 +348,14 @@ bool BufferStateLayer::setBuffer(const sp& buffer, const spgetBuffer() != mDrawingState.buffer->getBuffer()) { // If mCurrentState has a buffer, and we are about to update again // before swapping to drawing state, then the first buffer will be // dropped and we should decrement the pending buffer count and // call any release buffer callbacks if set. - callReleaseBufferCallback(mCurrentState.releaseBufferListener, mCurrentState.buffer, + callReleaseBufferCallback(mCurrentState.releaseBufferListener, + mCurrentState.buffer->getBuffer(), mCurrentState.acquireFence); decrementPendingBufferCount(); if (mCurrentState.bufferSurfaceFrameTX != nullptr) { @@ -396,8 +393,8 @@ bool BufferStateLayer::setBuffer(const sp& buffer, const spgetId(); + if (buffer && dequeueTime && *dequeueTime != 0) { + const uint64_t bufferId = buffer->getBuffer()->getId(); mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str()); mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, frameNumber, *dequeueTime, FrameTracer::FrameEvent::DEQUEUE); @@ -405,8 +402,8 @@ bool BufferStateLayer::setBuffer(const sp& buffer, const spwidth; - mCurrentState.height = mCurrentState.buffer->height; + mCurrentState.width = mCurrentState.buffer->getBuffer()->getWidth(); + mCurrentState.height = mCurrentState.buffer->getBuffer()->getHeight(); return true; } @@ -655,7 +652,7 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse } const int32_t layerId = getSequence(); - const uint64_t bufferId = mDrawingState.buffer->getId(); + const uint64_t bufferId = mDrawingState.buffer->getBuffer()->getId(); const uint64_t frameNumber = mDrawingState.frameNumber; const auto acquireFence = std::make_shared(mDrawingState.acquireFence); mFlinger->mTimeStats->setAcquireFence(layerId, frameNumber, acquireFence); @@ -689,7 +686,7 @@ status_t BufferStateLayer::updateActiveBuffer() { return BAD_VALUE; } - if (s.buffer != mBufferInfo.mBuffer) { + if (!mBufferInfo.mBuffer || s.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) { decrementPendingBufferCount(); } @@ -808,13 +805,13 @@ uint32_t BufferStateLayer::getEffectiveScalingMode() const { Rect BufferStateLayer::computeCrop(const State& s) { if (s.crop.isEmpty() && s.buffer) { - return s.buffer->getBounds(); + return s.buffer->getBuffer()->getBounds(); } else if (s.buffer) { Rect crop = s.crop; crop.left = std::max(crop.left, 0); crop.top = std::max(crop.top, 0); - uint32_t bufferWidth = s.buffer->getWidth(); - uint32_t bufferHeight = s.buffer->getHeight(); + uint32_t bufferWidth = s.buffer->getBuffer()->getWidth(); + uint32_t bufferHeight = s.buffer->getBuffer()->getHeight(); if (bufferHeight <= std::numeric_limits::max() && bufferWidth <= std::numeric_limits::max()) { crop.right = std::min(crop.right, static_cast(bufferWidth)); @@ -822,7 +819,7 @@ Rect BufferStateLayer::computeCrop(const State& s) { } if (!crop.isValid()) { // Crop rect is out of bounds, return whole buffer - return s.buffer->getBounds(); + return s.buffer->getBuffer()->getBounds(); } return crop; } @@ -844,8 +841,8 @@ bool BufferStateLayer::bufferNeedsFiltering() const { return false; } - uint32_t bufferWidth = s.buffer->width; - uint32_t bufferHeight = s.buffer->height; + uint32_t bufferWidth = s.buffer->getBuffer()->width; + uint32_t bufferHeight = s.buffer->getBuffer()->height; // Undo any transformations on the buffer and return the result. if (s.bufferTransform & ui::Transform::ROT_90) { @@ -872,14 +869,16 @@ void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) { ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers); } -void BufferStateLayer::bufferMayChange(sp& newBuffer) { - if (mDrawingState.buffer != nullptr && mDrawingState.buffer != mBufferInfo.mBuffer && - newBuffer != mDrawingState.buffer) { +void BufferStateLayer::bufferMayChange(const sp& newBuffer) { + if (mDrawingState.buffer != nullptr && + (!mBufferInfo.mBuffer || + mDrawingState.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) && + newBuffer != mDrawingState.buffer->getBuffer()) { // If we are about to update mDrawingState.buffer but it has not yet latched // then we will drop a buffer and should decrement the pending buffer count and // call any release buffer callbacks if set. - callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer, - mDrawingState.acquireFence); + callReleaseBufferCallback(mDrawingState.releaseBufferListener, + mDrawingState.buffer->getBuffer(), mDrawingState.acquireFence); decrementPendingBufferCount(); } } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 24e0ad290f..4171092b58 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -62,9 +62,9 @@ public: bool setTransform(uint32_t transform) override; bool setTransformToDisplayInverse(bool transformToDisplayInverse) override; bool setCrop(const Rect& crop) override; - bool setBuffer(const sp& buffer, const sp& acquireFence, nsecs_t postTime, - nsecs_t desiredPresentTime, bool isAutoTimestamp, - const client_cache_t& clientCacheId, uint64_t frameNumber, + bool setBuffer(const std::shared_ptr& buffer, + const sp& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime, + bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber, std::optional dequeueTime, const FrameTimelineInfo& info, const sp& transactionListener) override; bool setAcquireFence(const sp& fence) override; @@ -100,7 +100,7 @@ public: // See mPendingBufferTransactions void decrementPendingBufferCount(); - void bufferMayChange(sp& newBuffer) override; + void bufferMayChange(const sp& newBuffer) override; std::atomic* getPendingBufferCounter() override { return &mPendingBufferTransactions; } std::string getPendingBufferCounterName() override { return mBlastTransactionName; } diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp index 44b33ef43d..f310738423 100644 --- a/services/surfaceflinger/ClientCache.cpp +++ b/services/surfaceflinger/ClientCache.cpp @@ -102,7 +102,12 @@ bool ClientCache::add(const client_cache_t& cacheId, const sp& bu return false; } - processBuffers[id].buffer = buffer; + LOG_ALWAYS_FATAL_IF(mRenderEngine == nullptr, + "Attempted to build the ClientCache before a RenderEngine instance was " + "ready!"); + processBuffers[id].buffer = std::make_shared< + renderengine::ExternalTexture>(buffer, *mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE); return true; } @@ -132,7 +137,7 @@ void ClientCache::erase(const client_cache_t& cacheId) { } } -sp ClientCache::get(const client_cache_t& cacheId) { +std::shared_ptr ClientCache::get(const client_cache_t& cacheId) { std::lock_guard lock(mMutex); ClientCacheBuffer* buf = nullptr; @@ -213,8 +218,8 @@ void ClientCache::dump(std::string& result) { auto &buffers = i.second.second; for (auto& [id, clientCacheBuffer] : buffers) { StringAppendF(&result, "\t ID: %d, Width/Height: %d,%d\n", (int)id, - (int)clientCacheBuffer.buffer->getWidth(), - (int)clientCacheBuffer.buffer->getHeight()); + (int)clientCacheBuffer.buffer->getBuffer()->getWidth(), + (int)clientCacheBuffer.buffer->getBuffer()->getHeight()); } } } diff --git a/services/surfaceflinger/ClientCache.h b/services/surfaceflinger/ClientCache.h index 0d597c8e05..a9b8177d70 100644 --- a/services/surfaceflinger/ClientCache.h +++ b/services/surfaceflinger/ClientCache.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,11 @@ public: bool add(const client_cache_t& cacheId, const sp& buffer); void erase(const client_cache_t& cacheId); - sp get(const client_cache_t& cacheId); + std::shared_ptr get(const client_cache_t& cacheId); + + // Always called immediately after setup. Will be set to non-null, and then should never be + // called again. + void setRenderEngine(renderengine::RenderEngine* renderEngine) { mRenderEngine = renderEngine; } void removeProcess(const wp& processToken); @@ -59,7 +64,7 @@ private: std::mutex mMutex; struct ClientCacheBuffer { - sp buffer; + std::shared_ptr buffer; std::set> recipients; }; std::map /*caching process*/, @@ -73,6 +78,7 @@ private: }; sp mDeathRecipient; + renderengine::RenderEngine* mRenderEngine = nullptr; bool getBuffer(const client_cache_t& cacheId, ClientCacheBuffer** outClientCacheBuffer) REQUIRES(mMutex); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index f680460242..daee83bd2c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -16,15 +16,16 @@ #pragma once -#include -#include - +#include #include #include #include #include #include +#include +#include + namespace android { class GraphicBuffer; @@ -80,7 +81,8 @@ public: virtual void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) = 0; // Allocates a buffer as scratch space for GPU composition - virtual sp dequeueBuffer(base::unique_fd* bufferFence) = 0; + virtual std::shared_ptr dequeueBuffer( + base::unique_fd* bufferFence) = 0; // Queues the drawn buffer for consumption by HWC. readyFence is the fence // which will fire when the buffer is ready for consumption. diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h index a1230b3c4d..a8d372c562 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h @@ -45,6 +45,8 @@ struct RenderSurfaceCreationArgs { // The DisplaySurface for this surface sp displaySurface; + + size_t maxTextureCacheSize; }; /** @@ -81,6 +83,11 @@ public: return *this; } + RenderSurfaceCreationArgsBuilder& setMaxTextureCacheSize(size_t maxTextureCacheSize) { + mArgs.maxTextureCacheSize = maxTextureCacheSize; + return *this; + } + private: RenderSurfaceCreationArgs mArgs; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index 48a54d6c66..c61ec5991b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -89,7 +89,7 @@ struct OutputLayerCompositionState { // Overrides the buffer, acquire fence, and display frame stored in LayerFECompositionState struct { - sp buffer = nullptr; + std::shared_ptr buffer = nullptr; sp acquireFence = nullptr; Rect displayFrame = {}; ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index 5127a6f314..a8a538003e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -16,12 +16,16 @@ #pragma once -#include - #include #include #include +#include +#include + +#include "renderengine/ExternalTexture.h" +#include "renderengine/RenderEngine.h" + struct ANativeWindow; namespace android { @@ -54,7 +58,8 @@ public: void setProtected(bool useProtected) override; status_t beginFrame(bool mustRecompose) override; void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) override; - sp dequeueBuffer(base::unique_fd* bufferFence) override; + std::shared_ptr dequeueBuffer( + base::unique_fd* bufferFence) override; void queueBuffer(base::unique_fd readyFence) override; void onPresentDisplayCompleted() override; void flip() override; @@ -66,7 +71,7 @@ public: // Testing void setPageFlipCountForTest(std::uint32_t); void setSizeForTest(const ui::Size&); - sp& mutableGraphicBufferForTest(); + std::shared_ptr& mutableTextureForTest(); base::unique_fd& mutableBufferReadyForTest(); private: @@ -75,10 +80,13 @@ private: // ANativeWindow being rendered into const sp mNativeWindow; - // Current buffer being rendered into - sp mGraphicBuffer; + + std::vector> mTextureCache; + // Current texture being rendered into + std::shared_ptr mTexture; const sp mDisplaySurface; ui::Size mSize; + const size_t mMaxTextureCacheSize; bool mProtected{false}; std::uint32_t mPageFlipCount{0}; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h index c5d03a7218..53f4a30fb8 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h @@ -66,7 +66,7 @@ public: const Rect& getBounds() const { return mBounds; } const Region& getVisibleRegion() const { return mVisibleRegion; } size_t getAge() const { return mAge; } - const sp& getBuffer() const { return mTexture.getBuffer(); } + const std::shared_ptr& getBuffer() const { return mTexture; } const sp& getDrawFence() const { return mDrawFence; } const ProjectionSpace& getOutputSpace() const { return mOutputSpace; } ui::Dataspace getOutputDataspace() const { return mOutputDataspace; } @@ -87,7 +87,7 @@ public: void setLastUpdate(std::chrono::steady_clock::time_point now) { mLastUpdate = now; } void append(const CachedSet& other) { - mTexture.setBuffer(nullptr, nullptr); + mTexture = nullptr; mOutputDataspace = ui::Dataspace::UNKNOWN; mDrawFence = nullptr; @@ -115,31 +115,7 @@ private: Region mVisibleRegion; size_t mAge = 0; - class Texture { - public: - ~Texture() { setBuffer(nullptr, nullptr); } - - void setBuffer(const sp& buffer, renderengine::RenderEngine* re) { - if (mRE && mBuffer) { - mRE->unbindExternalTextureBuffer(mBuffer->getId()); - } - - mBuffer = buffer; - mRE = re; - - if (mRE && mBuffer) { - mRE->cacheExternalTextureBuffer(mBuffer); - } - } - - const sp& getBuffer() const { return mBuffer; } - - private: - sp mBuffer = nullptr; - renderengine::RenderEngine* mRE = nullptr; - }; - - Texture mTexture; + std::shared_ptr mTexture; sp mDrawFence; ProjectionSpace mOutputSpace; ui::Dataspace mOutputDataspace; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index a0cae6fcbb..fe858c2817 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -39,7 +39,7 @@ public: MOCK_METHOD1(setBufferPixelFormat, void(ui::PixelFormat)); MOCK_METHOD1(beginFrame, status_t(bool mustRecompose)); MOCK_METHOD2(prepareFrame, void(bool, bool)); - MOCK_METHOD1(dequeueBuffer, sp(base::unique_fd*)); + MOCK_METHOD1(dequeueBuffer, std::shared_ptr(base::unique_fd*)); MOCK_METHOD1(queueBuffer, void(base::unique_fd)); MOCK_METHOD0(onPresentDisplayCompleted, void()); MOCK_METHOD0(flip, void()); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 3ac5433457..3468b204fc 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -14,8 +14,7 @@ * limitations under the License. */ -#include - +#include #include #include #include @@ -29,7 +28,9 @@ #include #include -#include +#include + +#include "renderengine/ExternalTexture.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push @@ -715,11 +716,11 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr bool skipLayer = false; if (layer->getState().overrideInfo.buffer != nullptr) { if (previousOverride != nullptr && - layer->getState().overrideInfo.buffer == previousOverride) { + layer->getState().overrideInfo.buffer->getBuffer() == previousOverride) { ALOGV("Skipping redundant buffer"); skipLayer = true; } - previousOverride = layer->getState().overrideInfo.buffer; + previousOverride = layer->getState().overrideInfo.buffer->getBuffer(); } const bool includeGeometry = refreshArgs.updatingGeometryThisFrame; @@ -978,14 +979,15 @@ std::optional Output::composeSurfaces( } base::unique_fd fd; - sp buf; + + std::shared_ptr tex; // If we aren't doing client composition on this output, but do have a // flipClientTarget request for this frame on this output, we still need to // dequeue a buffer. if (hasClientComposition || outputState.flipClientTarget) { - buf = mRenderSurface->dequeueBuffer(&fd); - if (buf == nullptr) { + tex = mRenderSurface->dequeueBuffer(&fd); + if (tex == nullptr) { ALOGW("Dequeuing buffer for display [%s] failed, bailing out of " "client composition for this frame", mName.c_str()); @@ -1030,13 +1032,14 @@ std::optional Output::composeSurfaces( // Check if the client composition requests were rendered into the provided graphic buffer. If // so, we can reuse the buffer and avoid client composition. if (mClientCompositionRequestCache) { - if (mClientCompositionRequestCache->exists(buf->getId(), clientCompositionDisplay, + if (mClientCompositionRequestCache->exists(tex->getBuffer()->getId(), + clientCompositionDisplay, clientCompositionLayers)) { outputCompositionState.reusedClientComposition = true; setExpensiveRenderingExpected(false); return readyFence; } - mClientCompositionRequestCache->add(buf->getId(), clientCompositionDisplay, + mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay, clientCompositionLayers); } @@ -1069,12 +1072,12 @@ std::optional Output::composeSurfaces( // over to RenderEngine, in which case this flag can be removed from the drawLayers interface. const bool useFramebufferCache = outputState.layerStackInternal; status_t status = - renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buf, + renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex, useFramebufferCache, std::move(fd), &readyFence); if (status != NO_ERROR && mClientCompositionRequestCache) { // If rendering was not successful, remove the request from the cache. - mClientCompositionRequestCache->remove(buf->getId()); + mClientCompositionRequestCache->remove(tex->getBuffer()->getId()); } auto& timeStats = getCompositionEngine().getTimeStats(); @@ -1151,9 +1154,9 @@ std::vector Output::generateClientCompositionRequests( std::vector results; if (layer->getState().overrideInfo.buffer != nullptr) { - if (layer->getState().overrideInfo.buffer != previousOverrideBuffer) { + if (layer->getState().overrideInfo.buffer->getBuffer() != previousOverrideBuffer) { results = layer->getOverrideCompositionList(); - previousOverrideBuffer = layer->getState().overrideInfo.buffer; + previousOverrideBuffer = layer->getState().overrideInfo.buffer->getBuffer(); ALOGV("Replacing [%s] with override in RE", layer->getLayerFE().getDebugName()); } else { ALOGV("Skipping redundant override buffer for [%s] in RE", diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index f640f85bca..9ca8914deb 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -537,7 +537,7 @@ void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer, sp buffer = outputIndependentState.buffer; sp acquireFence = outputIndependentState.acquireFence; if (getState().overrideInfo.buffer != nullptr) { - buffer = getState().overrideInfo.buffer; + buffer = getState().overrideInfo.buffer->getBuffer(); acquireFence = getState().overrideInfo.acquireFence; } @@ -699,7 +699,7 @@ std::vector OutputLayer::getOverrideCompositionList() co settings.geometry = renderengine::Geometry{ .boundaries = boundaries.toFloatRect(), }; - settings.bufferId = getState().overrideInfo.buffer->getId(); + settings.bufferId = getState().overrideInfo.buffer->getBuffer()->getId(); settings.source = renderengine::PixelSource{ .buffer = renderengine::Buffer{ .buffer = getState().overrideInfo.buffer, diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 3bef77dde1..ef50870615 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -25,8 +25,8 @@ #include #include #include - #include +#include #include #include #include @@ -63,7 +63,8 @@ RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display mDisplay(display), mNativeWindow(args.nativeWindow), mDisplaySurface(args.displaySurface), - mSize(args.displayWidth, args.displayHeight) { + mSize(args.displayWidth, args.displayHeight), + mMaxTextureCacheSize(args.maxTextureCacheSize) { LOG_ALWAYS_FATAL_IF(!mNativeWindow); } @@ -146,7 +147,8 @@ void RenderSurface::prepareFrame(bool usesClientComposition, bool usesDeviceComp } } -sp RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) { +std::shared_ptr RenderSurface::dequeueBuffer( + base::unique_fd* bufferFence) { ATRACE_CALL(); int fd = -1; ANativeWindowBuffer* buffer = nullptr; @@ -158,16 +160,41 @@ sp RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) { mDisplay.getName().c_str(), result); // Return fast here as we can't do much more - any rendering we do // now will just be wrong. - return mGraphicBuffer; + return mTexture; + } + + ALOGW_IF(mTexture != nullptr, "Clobbering a non-null pointer to a buffer [%p].", + mTexture->getBuffer()->getNativeBuffer()->handle); + + sp newBuffer = GraphicBuffer::from(buffer); + + std::shared_ptr texture; + + for (auto it = mTextureCache.begin(); it != mTextureCache.end(); it++) { + const auto& cachedTexture = *it; + if (cachedTexture->getBuffer()->getId() == newBuffer->getId()) { + texture = cachedTexture; + mTextureCache.erase(it); + break; + } } - ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].", - mGraphicBuffer->getNativeBuffer()->handle); - mGraphicBuffer = GraphicBuffer::from(buffer); + if (texture) { + mTexture = texture; + } else { + mTexture = std::make_shared< + renderengine::ExternalTexture>(GraphicBuffer::from(buffer), + mCompositionEngine.getRenderEngine(), + renderengine::ExternalTexture::Usage::WRITEABLE); + } + mTextureCache.push_back(mTexture); + if (mTextureCache.size() > mMaxTextureCacheSize) { + mTextureCache.erase(mTextureCache.begin()); + } *bufferFence = base::unique_fd(fd); - return mGraphicBuffer; + return mTexture; } void RenderSurface::queueBuffer(base::unique_fd readyFence) { @@ -177,24 +204,24 @@ void RenderSurface::queueBuffer(base::unique_fd readyFence) { // hasFlipClientTargetRequest could return true even if we haven't // dequeued a buffer before. Try dequeueing one if we don't have a // buffer ready. - if (mGraphicBuffer == nullptr) { + if (mTexture == nullptr) { ALOGI("Attempting to queue a client composited buffer without one " "previously dequeued for display [%s]. Attempting to dequeue " "a scratch buffer now", mDisplay.getName().c_str()); - // We shouldn't deadlock here, since mGraphicBuffer == nullptr only + // We shouldn't deadlock here, since mTexture == nullptr only // after a successful call to queueBuffer, or if dequeueBuffer has // never been called. base::unique_fd unused; dequeueBuffer(&unused); } - if (mGraphicBuffer == nullptr) { + if (mTexture == nullptr) { ALOGE("No buffer is ready for display [%s]", mDisplay.getName().c_str()); } else { - status_t result = - mNativeWindow->queueBuffer(mNativeWindow.get(), - mGraphicBuffer->getNativeBuffer(), dup(readyFence)); + status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(), + mTexture->getBuffer()->getNativeBuffer(), + dup(readyFence)); if (result != NO_ERROR) { ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(), result); @@ -204,11 +231,12 @@ void RenderSurface::queueBuffer(base::unique_fd readyFence) { LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result); } else { mNativeWindow->cancelBuffer(mNativeWindow.get(), - mGraphicBuffer->getNativeBuffer(), dup(readyFence)); + mTexture->getBuffer()->getNativeBuffer(), + dup(readyFence)); } } - mGraphicBuffer = nullptr; + mTexture = nullptr; } } @@ -256,8 +284,8 @@ void RenderSurface::setSizeForTest(const ui::Size& size) { mSize = size; } -sp& RenderSurface::mutableGraphicBufferForTest() { - return mGraphicBuffer; +std::shared_ptr& RenderSurface::mutableTextureForTest() { + return mTexture; } } // namespace impl diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index dcb75556e3..9955e29f4a 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -130,7 +130,7 @@ bool CachedSet::hasBufferUpdate() const { } bool CachedSet::hasReadyBuffer() const { - return mTexture.getBuffer() != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled; + return mTexture != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled; } std::vector CachedSet::decompose() const { @@ -217,21 +217,27 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, sp buffer = new GraphicBuffer(static_cast(mBounds.getWidth()), static_cast(mBounds.getHeight()), HAL_PIXEL_FORMAT_RGBA_8888, 1, usageFlags); + const auto texture = std::make_shared< + renderengine::ExternalTexture>(buffer, renderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); LOG_ALWAYS_FATAL_IF(buffer->initCheck() != OK); base::unique_fd drawFence; - status_t result = renderEngine.drawLayers(displaySettings, layerSettingsPointers, buffer, false, - base::unique_fd(), &drawFence); + status_t result = renderEngine.drawLayers(displaySettings, layerSettingsPointers, texture, + false, base::unique_fd(), &drawFence); if (result == NO_ERROR) { - mTexture.setBuffer(buffer, &renderEngine); mDrawFence = new Fence(drawFence.release()); mOutputSpace = ProjectionSpace(ui::Size(outputState.framebufferSpace.bounds.getWidth(), outputState.framebufferSpace.bounds.getHeight()), mBounds); + mTexture = std::move(texture); mOutputSpace.orientation = outputState.framebufferSpace.orientation; mOutputDataspace = outputDataspace; mOrientation = orientation; + } else { + mTexture = nullptr; } } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp index ad7555730d..3a2534b847 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp @@ -111,7 +111,12 @@ void Planner::reportFinalPlan( const GraphicBuffer* currentOverrideBuffer = nullptr; bool hasSkippedLayers = false; for (auto layer : layers) { - const GraphicBuffer* overrideBuffer = layer->getState().overrideInfo.buffer.get(); + if (!layer->getState().overrideInfo.buffer) { + continue; + } + + const GraphicBuffer* overrideBuffer = + layer->getState().overrideInfo.buffer->getBuffer().get(); if (overrideBuffer != nullptr && overrideBuffer == currentOverrideBuffer) { // Skip this layer since it is part of a previous cached set hasSkippedLayers = true; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 8a4d161289..4c3f4940cc 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -26,6 +26,7 @@ #include "MockHWC2.h" #include "MockHWComposer.h" #include "RegionMatcher.h" +#include "renderengine/mock/RenderEngine.h" namespace android::compositionengine { namespace { @@ -715,7 +716,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static const HdrMetadata kHdrMetadata; static native_handle_t* kSidebandStreamHandle; static const sp kBuffer; - static const sp kOverrideBuffer; + std::shared_ptr kOverrideBuffer; static const sp kFence; static const sp kOverrideFence; static const std::string kLayerGenericMetadata1Key; @@ -724,6 +725,11 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static const std::vector kLayerGenericMetadata2Value; OutputLayerWriteStateToHWCTest() { + kOverrideBuffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage:: + WRITEABLE); auto& outputLayerState = mOutputLayer.editState(); outputLayerState.hwc = impl::OutputLayerCompositionState::Hwc(mHwcLayer); @@ -839,6 +845,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { std::shared_ptr mHwcLayer{std::make_shared>()}; StrictMock mDisplayColorProfile; + renderengine::mock::RenderEngine mRenderEngine; }; const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 83.f / 255.f, @@ -858,7 +865,6 @@ const HdrMetadata OutputLayerWriteStateToHWCTest::kHdrMetadata{{/* LightFlattena native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle = reinterpret_cast(1031); const sp OutputLayerWriteStateToHWCTest::kBuffer; -const sp OutputLayerWriteStateToHWCTest::kOverrideBuffer = new GraphicBuffer(); const sp OutputLayerWriteStateToHWCTest::kFence; const sp OutputLayerWriteStateToHWCTest::kOverrideFence = new Fence(); const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key = @@ -1023,7 +1029,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { kOverrideBufferTransform, kOverrideBlendMode, kOverrideAlpha); expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion, kOverrideSurfaceDamage); - expectSetHdrMetadataAndBufferCalls(kOverrideBuffer, kOverrideFence); + expectSetHdrMetadataAndBufferCalls(kOverrideBuffer->getBuffer(), kOverrideFence); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 5f0b0eea15..e80100cc6e 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#include - #include #include #include @@ -31,9 +29,12 @@ #include #include +#include + #include "CallOrderStateMachineHelper.h" #include "MockHWC2.h" #include "RegionMatcher.h" +#include "renderengine/ExternalTexture.h" namespace android::compositionengine { namespace { @@ -2960,7 +2961,10 @@ struct OutputComposeSurfacesTest : public testing::Test { mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock(); mock::RenderSurface* mRenderSurface = new StrictMock(); StrictMock mOutput; - sp mOutputBuffer = new GraphicBuffer(); + std::shared_ptr mOutputBuffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); std::optional mReadyFence; }; @@ -3173,7 +3177,10 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) { EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _)) .WillRepeatedly(Return()); - sp otherOutputBuffer = new GraphicBuffer(); + const auto otherOutputBuffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)) .WillOnce(Return(mOutputBuffer)) .WillOnce(Return(otherOutputBuffer)); diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 5ef5d7b5cb..9aeb290eb5 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -15,6 +15,8 @@ */ // TODO(b/129481165): remove the #pragma below and fix conversion issues +#include "renderengine/ExternalTexture.h" +#include "ui/GraphicBuffer.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wextra" @@ -239,9 +241,9 @@ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) { DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR))); base::unique_fd fence; - EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer(&fence).get()); + EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer(&fence)->getBuffer().get()); - EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(buffer.get(), mSurface.mutableTextureForTest()->getBuffer().get()); } /* @@ -249,8 +251,11 @@ TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) { */ TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { - sp buffer = new GraphicBuffer(); - mSurface.mutableGraphicBufferForTest() = buffer; + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(), mRenderEngine, + renderengine::ExternalTexture::Usage::READABLE | + renderengine::ExternalTexture::Usage::WRITEABLE); + mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = false; @@ -261,43 +266,45 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) { mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(buffer.get(), mSurface.mutableTextureForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) { - sp buffer = new GraphicBuffer(); - mSurface.mutableGraphicBufferForTest() = buffer; + const auto buffer = std::make_shared(new GraphicBuffer(), + mRenderEngine, false); + mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = true; state.flipClientTarget = false; EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); - EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) { - sp buffer = new GraphicBuffer(); - mSurface.mutableGraphicBufferForTest() = buffer; + const auto buffer = std::make_shared(new GraphicBuffer(), + mRenderEngine, false); + mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = false; state.flipClientTarget = true; EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); - EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) { @@ -317,27 +324,28 @@ TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferY mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); } TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) { - sp buffer = new GraphicBuffer(); - mSurface.mutableGraphicBufferForTest() = buffer; + const auto buffer = std::make_shared(new GraphicBuffer(), + mRenderEngine, false); + mSurface.mutableTextureForTest() = buffer; impl::OutputCompositionState state; state.usesClientComposition = true; EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state)); - EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) .WillOnce(Return(INVALID_OPERATION)); EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true)); - EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getNativeBuffer(), -1)) + EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getBuffer()->getNativeBuffer(), -1)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1); mSurface.queueBuffer(base::unique_fd()); - EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get()); + EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get()); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index f01fe27b38..283c69270f 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -305,8 +305,8 @@ TEST_F(CachedSetTest, render) { const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, const std::vector& layers, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> size_t { + const std::shared_ptr&, const bool, + base::unique_fd&&, base::unique_fd*) -> size_t { EXPECT_EQ(Rect(0, 0, 2, 2), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation), @@ -321,7 +321,6 @@ TEST_F(CachedSetTest, render) { EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1)); EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2)); EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers)); - EXPECT_CALL(mRenderEngine, cacheExternalTextureBuffer(_)); cachedSet.render(mRenderEngine, mOutputState); expectReadyBuffer(cachedSet); @@ -331,7 +330,6 @@ TEST_F(CachedSetTest, render) { cachedSet.getOutputSpace().bounds); // Now check that appending a new cached set properly cleans up RenderEngine resources. - EXPECT_CALL(mRenderEngine, unbindExternalTextureBuffer(_)); CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get(); cachedSet.append(CachedSet(layer3)); } diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index b7b2cc691b..8692ee60dc 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -70,11 +70,13 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) mIsPrimary(args.isPrimary) { mCompositionDisplay->editState().isSecure = args.isSecure; mCompositionDisplay->createRenderSurface( - compositionengine::RenderSurfaceCreationArgs{ANativeWindow_getWidth( - args.nativeWindow.get()), - ANativeWindow_getHeight( - args.nativeWindow.get()), - args.nativeWindow, args.displaySurface}); + compositionengine:: + RenderSurfaceCreationArgs{ANativeWindow_getWidth(args.nativeWindow.get()), + ANativeWindow_getHeight(args.nativeWindow.get()), + args.nativeWindow, args.displaySurface, + static_cast( + SurfaceFlinger:: + maxFrameBufferAcquiredBuffers)}); if (!mFlinger->mDisableClientCompositionCache && SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b45f2bcd92..cf215adba2 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -880,7 +880,7 @@ uint32_t Layer::doTransaction(uint32_t flags) { } // Allow BufferStateLayer to release any unlatched buffers in drawing state. - bufferMayChange(c.buffer); + bufferMayChange(c.buffer->getBuffer()); // Commit the transaction commitTransaction(c); @@ -891,7 +891,11 @@ uint32_t Layer::doTransaction(uint32_t flags) { void Layer::commitTransaction(State& stateToCommit) { if (auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX; - mDrawingState.buffer != stateToCommit.buffer && bufferSurfaceFrame != nullptr && + ((mDrawingState.buffer && stateToCommit.buffer && + mDrawingState.buffer->getBuffer() != stateToCommit.buffer->getBuffer()) || + (mDrawingState.buffer && !stateToCommit.buffer) || + (!mDrawingState.buffer && stateToCommit.buffer)) && + bufferSurfaceFrame != nullptr && bufferSurfaceFrame->getPresentState() != PresentState::Presented) { // If the previous buffer was committed but not latched (refreshPending - happens during // back to back invalidates), it gets silently dropped here. Mark the corresponding diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 5379d7490d..9f3ea9ab39 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -203,7 +203,7 @@ public: Region transparentRegionHint; - sp buffer; + std::shared_ptr buffer; client_cache_t clientCacheId; sp acquireFence; std::shared_ptr acquireFenceTime; @@ -404,10 +404,11 @@ public: // Used only to set BufferStateLayer state virtual bool setTransform(uint32_t /*transform*/) { return false; }; virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; }; - virtual bool setBuffer(const sp& /*buffer*/, const sp& /*acquireFence*/, - nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/, - bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/, - uint64_t /* frameNumber */, std::optional /* dequeueTime */, + virtual bool setBuffer(const std::shared_ptr& /*buffer*/, + const sp& /*acquireFence*/, nsecs_t /*postTime*/, + nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, + const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */, + std::optional /* dequeueTime */, const FrameTimelineInfo& /*info*/, const sp& /* releaseBufferListener */) { return false; @@ -709,7 +710,7 @@ public: * Called before updating the drawing state buffer. Used by BufferStateLayer to release any * unlatched buffers in the drawing state. */ - virtual void bufferMayChange(sp& /* newBuffer */){}; + virtual void bufferMayChange(const sp& /* newBuffer */){}; /* * Remove relative z for the layer if its relative parent is not part of the diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 7a3e433660..a9fd16cb75 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -208,7 +208,8 @@ bool RefreshRateOverlay::createLayer() { return true; } -const std::vector>& RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { +const std::vector>& +RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { if (mBufferCache.find(fps) == mBufferCache.end()) { // Ensure the range is > 0, so we don't divide by 0. const auto rangeLength = std::max(1u, mHighFps - mLowFps); @@ -222,7 +223,17 @@ const std::vector>& RefreshRateOverlay::getOrCreateBuffers(uin color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale); color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale); color.a = ALPHA; - mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner)); + auto buffers = SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner); + std::vector> textures; + std::transform(buffers.begin(), buffers.end(), std::back_inserter(textures), + [&](const auto& buffer) -> std::shared_ptr { + return std::make_shared< + renderengine::ExternalTexture>(buffer, + mFlinger.getRenderEngine(), + renderengine::ExternalTexture:: + Usage::READABLE); + }); + mBufferCache.emplace(fps, textures); } return mBufferCache[fps]; diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index c16cfa07a4..aa8329c46a 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -16,13 +16,14 @@ #pragma once -#include - #include +#include #include #include #include +#include + #include "Fps.h" namespace android { @@ -70,7 +71,8 @@ private: }; bool createLayer(); - const std::vector>& getOrCreateBuffers(uint32_t fps); + const std::vector>& getOrCreateBuffers( + uint32_t fps); SurfaceFlinger& mFlinger; const sp mClient; @@ -78,7 +80,8 @@ private: sp mIBinder; sp mGbp; - std::unordered_map>> mBufferCache; + std::unordered_map>> + mBufferCache; std::optional mCurrentFps; int mFrame = 0; static constexpr float ALPHA = 0.8f; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index d0032ac7fd..00090d948a 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -438,18 +438,22 @@ void RegionSamplingThread::captureSample() { mFlinger.traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, filterVisitor); }; - sp buffer = nullptr; - if (mCachedBuffer && mCachedBuffer->getWidth() == sampledBounds.getWidth() && - mCachedBuffer->getHeight() == sampledBounds.getHeight()) { + std::shared_ptr buffer = nullptr; + if (mCachedBuffer && mCachedBuffer->getBuffer()->getWidth() == sampledBounds.getWidth() && + mCachedBuffer->getBuffer()->getHeight() == sampledBounds.getHeight()) { buffer = mCachedBuffer; } else { const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), - PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); - const status_t bufferStatus = buffer->initCheck(); + sp graphicBuffer = + new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(), + PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread"); + const status_t bufferStatus = graphicBuffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d", bufferStatus); + buffer = std::make_shared< + renderengine::ExternalTexture>(graphicBuffer, mFlinger.getRenderEngine(), + renderengine::ExternalTexture::Usage::WRITEABLE); } const sp captureListener = new SyncScreenCaptureListener(); @@ -465,8 +469,8 @@ void RegionSamplingThread::captureSample() { } ALOGV("Sampling %zu descriptors", activeDescriptors.size()); - std::vector lumas = - sampleBuffer(buffer, sampledBounds.leftTop(), activeDescriptors, orientation); + std::vector lumas = sampleBuffer(buffer->getBuffer(), sampledBounds.leftTop(), + activeDescriptors, orientation); if (lumas.size() != activeDescriptors.size()) { ALOGW("collected %zu median luma values for %zu descriptors", lumas.size(), activeDescriptors.size()); @@ -477,16 +481,6 @@ void RegionSamplingThread::captureSample() { activeDescriptors[d].listener->onSampleCollected(lumas[d]); } - // Extend the lifetime of mCachedBuffer from the previous frame to here to ensure that: - // 1) The region sampling thread is the last owner of the buffer, and the freeing of the buffer - // happens in this thread, as opposed to the main thread. - // 2) The listener(s) receive their notifications prior to freeing the buffer. - if (mCachedBuffer != nullptr && mCachedBuffer != buffer) { - if (mFlinger.getRenderEngine().getRenderEngineType() == - renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) { - mFlinger.getRenderEngine().unbindExternalTextureBuffer(mCachedBuffer->getId()); - } - } mCachedBuffer = buffer; ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::noWorkNeeded)); } diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h index 0defdb3fcb..86632db490 100644 --- a/services/surfaceflinger/RegionSamplingThread.h +++ b/services/surfaceflinger/RegionSamplingThread.h @@ -16,17 +16,19 @@ #pragma once +#include +#include +#include +#include +#include +#include + #include #include #include #include #include -#include -#include -#include -#include -#include #include "Scheduler/OneShotTimer.h" namespace android { @@ -122,7 +124,8 @@ private: std::mutex mSamplingMutex; std::unordered_map, Descriptor, WpHash> mDescriptors GUARDED_BY(mSamplingMutex); - sp mCachedBuffer GUARDED_BY(mSamplingMutex) = nullptr; + std::shared_ptr mCachedBuffer GUARDED_BY(mSamplingMutex) = + nullptr; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a4803df9f0..21c8193ca1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -727,6 +727,7 @@ void SurfaceFlinger::init() { mCompositionEngine->setTimeStats(mTimeStats); mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName)); mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId); + ClientCache::getInstance().setRenderEngine(&getRenderEngine()); // Process any initial hotplug and resulting display changes. processDisplayHotplugEventsLocked(); const auto display = getDefaultDisplayDeviceLocked(); @@ -3692,7 +3693,6 @@ void SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin if (uncacheBuffer.isValid()) { ClientCache::getInstance().erase(uncacheBuffer); - getRenderEngine().unbindExternalTextureBuffer(uncacheBuffer.id); } // If a synchronous transaction is explicitly requested without any changes, force a transaction @@ -4056,23 +4056,16 @@ uint32_t SurfaceFlinger::setClientStateLocked( } bool bufferChanged = what & layer_state_t::eBufferChanged; bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged; - sp buffer; + std::shared_ptr buffer; if (bufferChanged && cacheIdChanged && s.buffer != nullptr) { - buffer = s.buffer; - bool success = ClientCache::getInstance().add(s.cachedBuffer, s.buffer); - if (success) { - getRenderEngine().cacheExternalTextureBuffer(s.buffer); - success = ClientCache::getInstance() - .registerErasedRecipient(s.cachedBuffer, - wp(this)); - if (!success) { - getRenderEngine().unbindExternalTextureBuffer(s.buffer->getId()); - } - } + ClientCache::getInstance().add(s.cachedBuffer, s.buffer); + buffer = ClientCache::getInstance().get(s.cachedBuffer); } else if (cacheIdChanged) { buffer = ClientCache::getInstance().get(s.cachedBuffer); - } else if (bufferChanged) { - buffer = s.buffer; + } else if (bufferChanged && s.buffer != nullptr) { + buffer = std::make_shared< + renderengine::ExternalTexture>(s.buffer, getRenderEngine(), + renderengine::ExternalTexture::Usage::READABLE); } if (buffer) { const bool frameNumberChanged = what & layer_state_t::eFrameNumberChanged; @@ -5993,15 +5986,17 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, const status_t bufferStatus = buffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d", bufferStatus); - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, + const auto texture = std::make_shared< + renderengine::ExternalTexture>(buffer, getRenderEngine(), + renderengine::ExternalTexture::Usage::WRITEABLE); + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, texture, false /* regionSampling */, grayscale, captureListener); } -status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, - TraverseLayersFunction traverseLayers, - sp& buffer, bool regionSampling, - bool grayscale, - const sp& captureListener) { +status_t SurfaceFlinger::captureScreenCommon( + RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, + const std::shared_ptr& buffer, bool regionSampling, + bool grayscale, const sp& captureListener) { ATRACE_CALL(); if (captureListener == nullptr) { @@ -6034,15 +6029,6 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, regionSampling, grayscale, captureResults); }); - // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine - // Only do this when we're not doing region sampling, to allow the region sampling thread to - // manage buffer lifecycle itself. - if (!regionSampling && - getRenderEngine().getRenderEngineType() == - renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) { - getRenderEngine().unbindExternalTextureBuffer(buffer->getId()); - } - captureResults.result = result; captureListener->onScreenCaptureCompleted(captureResults); })); @@ -6050,11 +6036,10 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, return NO_ERROR; } -status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, - TraverseLayersFunction traverseLayers, - const sp& buffer, bool forSystem, - bool regionSampling, bool grayscale, - ScreenCaptureResults& captureResults) { +status_t SurfaceFlinger::renderScreenImplLocked( + const RenderArea& renderArea, TraverseLayersFunction traverseLayers, + const std::shared_ptr& buffer, bool forSystem, + bool regionSampling, bool grayscale, ScreenCaptureResults& captureResults) { ATRACE_CALL(); traverseLayers([&](Layer* layer) { @@ -6062,7 +6047,7 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure()); }); - const bool useProtected = buffer->getUsage() & GRALLOC_USAGE_PROTECTED; + const bool useProtected = buffer->getBuffer()->getUsage() & GRALLOC_USAGE_PROTECTED; // We allow the system server to take screenshots of secure layers for // use in situations like the Screen-rotation animation and place @@ -6072,7 +6057,7 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, return PERMISSION_DENIED; } - captureResults.buffer = buffer; + captureResults.buffer = buffer->getBuffer(); captureResults.capturedDataspace = renderArea.getReqDataSpace(); const auto reqWidth = renderArea.getReqWidth(); @@ -6163,11 +6148,9 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, base::unique_fd drawFence; getRenderEngine().useProtectedContext(useProtected); - // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine - const bool useFramebufferCache = getRenderEngine().getRenderEngineType() == - renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED; + const constexpr bool kUseFramebufferCache = false; getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer, - useFramebufferCache, std::move(bufferFence), &drawFence); + kUseFramebufferCache, std::move(bufferFence), &drawFence); if (drawFence >= 0) { sp releaseFence = new Fence(dup(drawFence)); @@ -6432,10 +6415,6 @@ void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) { mOffscreenLayers.erase(layer); } -void SurfaceFlinger::bufferErased(const client_cache_t& clientCacheId) { - getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id); -} - status_t SurfaceFlinger::setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 9135632bef..893b3d8751 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -178,7 +178,6 @@ struct SurfaceFlingerBE { class SurfaceFlinger : public BnSurfaceComposer, public PriorityDumper, - public ClientCache::ErasedRecipient, private IBinder::DeathRecipient, private HWC2::ComposerCallback, private ISchedulerCallback { @@ -326,9 +325,6 @@ public: wp fromHandle(const sp& handle); wp fromHandleLocked(const sp& handle) const REQUIRES(mStateLock); - // Inherit from ClientCache::ErasedRecipient - void bufferErased(const client_cache_t& clientCacheId) override; - // If set, disables reusing client composition buffers. This can be set by // debug.sf.disable_client_composition_cache bool mDisableClientCompositionCache = false; @@ -901,12 +897,14 @@ private: status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, ui::PixelFormat, bool allowProtected, bool grayscale, const sp&); - status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp&, + status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, + const std::shared_ptr&, bool regionSampling, bool grayscale, const sp&); status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction, - const sp&, bool forSystem, bool regionSampling, - bool grayscale, ScreenCaptureResults&); + const std::shared_ptr&, + bool forSystem, bool regionSampling, bool grayscale, + ScreenCaptureResults&); sp getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); sp getDisplayById(DisplayId displayId) const REQUIRES(mStateLock); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 4e1c0c77ea..3042450f29 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -15,6 +15,7 @@ */ // TODO(b/129481165): remove the #pragma below and fix conversion issues +#include "renderengine/ExternalTexture.h" #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wextra" @@ -194,7 +195,7 @@ public: sp mClientTargetAcquireFence = Fence::NO_FENCE; - sp mCaptureScreenBuffer; + std::shared_ptr mCaptureScreenBuffer; }; template @@ -243,11 +244,15 @@ void CompositionTest::captureScreenComposition() { // TODO: Eliminate expensive/real allocation if possible. const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - mCaptureScreenBuffer = new GraphicBuffer(renderArea->getReqWidth(), renderArea->getReqHeight(), - HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot"); + mCaptureScreenBuffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(renderArea->getReqWidth(), + renderArea->getReqHeight(), + HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, + "screenshot"), + *mRenderEngine, true); status_t result = - mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer.get(), + mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer, forSystem, regionSampling); EXPECT_EQ(NO_ERROR, result); @@ -340,8 +345,8 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings, const std::vector&, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr&, + const bool, base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -389,8 +394,8 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings, const std::vector&, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr&, + const bool, base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -625,8 +630,8 @@ struct BaseLayerProperties { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings& displaySettings, const std::vector& layerSettings, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr&, const bool, + base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -674,8 +679,8 @@ struct BaseLayerProperties { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings& displaySettings, const std::vector& layerSettings, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr&, const bool, + base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -751,8 +756,8 @@ struct CommonSecureLayerProperties : public BaseLayerProperties EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([](const renderengine::DisplaySettings& displaySettings, const std::vector& layerSettings, - const sp&, const bool, base::unique_fd&&, - base::unique_fd*) -> status_t { + const std::shared_ptr&, const bool, + base::unique_fd&&, base::unique_fd*) -> status_t { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 63baf7dee2..d004b9d9eb 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -352,8 +352,8 @@ public: auto renderScreenImplLocked(const RenderArea& renderArea, SurfaceFlinger::TraverseLayersFunction traverseLayers, - const sp& buffer, bool forSystem, - bool regionSampling) { + const std::shared_ptr& buffer, + bool forSystem, bool regionSampling) { ScreenCaptureResults captureResults; return mFlinger->renderScreenImplLocked(renderArea, traverseLayers, buffer, forSystem, regionSampling, false /* grayscale */, diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index ea1ce47b70..25001d3890 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include "TestableSurfaceFlinger.h" @@ -99,6 +101,7 @@ public: TestableSurfaceFlinger mFlinger; Hwc2::mock::Composer* mComposer = nullptr; + renderengine::mock::RenderEngine mRenderEngine; FenceToFenceTimeMap fenceFactory; client_cache_t mClientCache; @@ -106,9 +109,12 @@ public: sp layer = createBufferStateLayer(); sp fence(new Fence()); - sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); int32_t layerId = layer->getSequence(); - uint64_t bufferId = buffer->getId(); + uint64_t bufferId = buffer->getBuffer()->getId(); uint64_t frameNumber = 5; nsecs_t dequeueTime = 10; nsecs_t postTime = 20; diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index 09a1c2af75..b7917aa00e 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include "TestableSurfaceFlinger.h" @@ -99,6 +101,7 @@ public: TestableSurfaceFlinger mFlinger; Hwc2::mock::Composer* mComposer = nullptr; + renderengine::mock::RenderEngine mRenderEngine; FenceToFenceTimeMap fenceFactory; client_cache_t mClientCache; @@ -119,7 +122,10 @@ public: sp layer = createBufferStateLayer(); sp fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence->signalForTest(12); @@ -144,7 +150,10 @@ public: sp fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer1 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -153,7 +162,10 @@ public: sp fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - sp buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer2 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); nsecs_t start = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); @@ -191,8 +203,10 @@ public: sp fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; - + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence->signalForTest(12); @@ -217,8 +231,10 @@ public: sp layer = createBufferStateLayer(); sp fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; - + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -247,8 +263,10 @@ public: sp fence(new Fence()); auto acquireFence = fenceFactory.createFenceTimeForTest(fence); - sp buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; - + const auto buffer = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -283,7 +301,10 @@ public: sp fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer1 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); @@ -291,7 +312,10 @@ public: sp fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - sp buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer2 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); acquireFence2->signalForTest(12); @@ -318,7 +342,10 @@ public: sp fence1(new Fence()); auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1); - sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer1 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); @@ -327,7 +354,10 @@ public: sp fence2(new Fence()); auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2); - sp buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer2 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); auto dropStartTime1 = systemTime(); layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0}, @@ -339,7 +369,10 @@ public: sp fence3(new Fence()); auto acquireFence3 = fenceFactory.createFenceTimeForTest(fence3); - sp buffer3{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer3 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, + 1, 0), + mRenderEngine, false); auto dropStartTime2 = systemTime(); layer->setBuffer(buffer3, fence3, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); @@ -379,7 +412,11 @@ public: std::vector> bufferlessSurfaceFrames; for (int i = 0; i < 10; i += 2) { sp fence1(new Fence()); - sp buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; + const auto buffer1 = std::make_shared< + renderengine::ExternalTexture>(new GraphicBuffer(1, 1, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + 0), + mRenderEngine, false); layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt, {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */); -- cgit v1.2.3-59-g8ed1b From 562c2718fcf8f465fe54a88c7ac948cd21a77ce5 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 7 May 2021 15:10:42 -0700 Subject: SF: region sampling scheduling optimization Schedule the region sampling thread more wisely by estimating when the next invalidate is going to happen. This makes the region sampling to be scheduled often at times where the main thread is idle, without eating the budget in an invalidate message. Bug: 181983990 Test: SF unit tests Test: observe systrace Change-Id: I1faca3aa7f882ed7c69e77e6a0877c10d57f0f1c --- services/surfaceflinger/RegionSamplingThread.cpp | 127 ++++----------------- services/surfaceflinger/RegionSamplingThread.h | 26 ++--- services/surfaceflinger/Scheduler/MessageQueue.cpp | 47 +++++--- services/surfaceflinger/Scheduler/MessageQueue.h | 15 ++- services/surfaceflinger/SurfaceFlinger.cpp | 21 +++- services/surfaceflinger/SurfaceFlinger.h | 3 + .../tests/unittests/MessageQueueTest.cpp | 20 +++- .../tests/unittests/mock/MockMessageQueue.h | 1 + 8 files changed, 116 insertions(+), 144 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 00090d948a..653aca6cde 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -56,16 +56,14 @@ enum class samplingStep { noWorkNeeded, idleTimerWaiting, waitForQuietFrame, - waitForZeroPhase, waitForSamplePhase, sample }; -constexpr auto timeForRegionSampling = 5000000ns; -constexpr auto maxRegionSamplingSkips = 10; constexpr auto defaultRegionSamplingWorkDuration = 3ms; constexpr auto defaultRegionSamplingPeriod = 100ms; constexpr auto defaultRegionSamplingTimerTimeout = 100ms; +constexpr auto maxRegionSamplingDelay = 100ms; // TODO: (b/127403193) duration to string conversion could probably be constexpr template inline std::string toNsString(std::chrono::duration t) { @@ -99,97 +97,22 @@ RegionSamplingThread::EnvironmentTimingTunables::EnvironmentTimingTunables() { } } -struct SamplingOffsetCallback : VSyncSource::Callback { - SamplingOffsetCallback(RegionSamplingThread& samplingThread, Scheduler& scheduler, - std::chrono::nanoseconds targetSamplingWorkDuration) - : mRegionSamplingThread(samplingThread), - mTargetSamplingWorkDuration(targetSamplingWorkDuration), - mVSyncSource(scheduler.makePrimaryDispSyncSource("SamplingThreadDispSyncListener", 0ns, - 0ns, - /*traceVsync=*/false)) { - mVSyncSource->setCallback(this); - } - - ~SamplingOffsetCallback() { stopVsyncListener(); } - - SamplingOffsetCallback(const SamplingOffsetCallback&) = delete; - SamplingOffsetCallback& operator=(const SamplingOffsetCallback&) = delete; - - void startVsyncListener() { - std::lock_guard lock(mMutex); - if (mVsyncListening) return; - - mPhaseIntervalSetting = Phase::ZERO; - mVSyncSource->setVSyncEnabled(true); - mVsyncListening = true; - } - - void stopVsyncListener() { - std::lock_guard lock(mMutex); - stopVsyncListenerLocked(); - } - -private: - void stopVsyncListenerLocked() /*REQUIRES(mMutex)*/ { - if (!mVsyncListening) return; - - mVSyncSource->setVSyncEnabled(false); - mVsyncListening = false; - } - - void onVSyncEvent(nsecs_t /*when*/, nsecs_t /*expectedVSyncTimestamp*/, - nsecs_t /*deadlineTimestamp*/) final { - std::unique_lock lock(mMutex); - - if (mPhaseIntervalSetting == Phase::ZERO) { - ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::waitForSamplePhase)); - mPhaseIntervalSetting = Phase::SAMPLING; - mVSyncSource->setDuration(mTargetSamplingWorkDuration, 0ns); - return; - } - - if (mPhaseIntervalSetting == Phase::SAMPLING) { - mPhaseIntervalSetting = Phase::ZERO; - mVSyncSource->setDuration(0ns, 0ns); - stopVsyncListenerLocked(); - lock.unlock(); - mRegionSamplingThread.notifySamplingOffset(); - return; - } - } - - RegionSamplingThread& mRegionSamplingThread; - const std::chrono::nanoseconds mTargetSamplingWorkDuration; - mutable std::mutex mMutex; - enum class Phase { - ZERO, - SAMPLING - } mPhaseIntervalSetting /*GUARDED_BY(mMutex) macro doesnt work with unique_lock?*/ - = Phase::ZERO; - bool mVsyncListening /*GUARDED_BY(mMutex)*/ = false; - std::unique_ptr mVSyncSource; -}; - -RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler, - const TimingTunables& tunables) +RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, const TimingTunables& tunables) : mFlinger(flinger), - mScheduler(scheduler), mTunables(tunables), mIdleTimer( "RegSampIdle", std::chrono::duration_cast( mTunables.mSamplingTimerTimeout), [] {}, [this] { checkForStaleLuma(); }), - mPhaseCallback(std::make_unique(*this, mScheduler, - tunables.mSamplingDuration)), - lastSampleTime(0ns) { + mLastSampleTime(0ns) { mThread = std::thread([this]() { threadMain(); }); pthread_setname_np(mThread.native_handle(), "RegionSampling"); mIdleTimer.start(); } -RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler) - : RegionSamplingThread(flinger, scheduler, +RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger) + : RegionSamplingThread(flinger, TimingTunables{defaultRegionSamplingWorkDuration, defaultRegionSamplingPeriod, defaultRegionSamplingTimerTimeout}) {} @@ -224,48 +147,46 @@ void RegionSamplingThread::removeListener(const sp& lis void RegionSamplingThread::checkForStaleLuma() { std::lock_guard lock(mThreadControlMutex); - if (mDiscardedFrames > 0) { - ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::waitForZeroPhase)); - mDiscardedFrames = 0; - mPhaseCallback->startVsyncListener(); + if (mSampleRequestTime.has_value()) { + ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::waitForSamplePhase)); + mSampleRequestTime.reset(); + mFlinger.scheduleRegionSamplingThread(); } } -void RegionSamplingThread::notifyNewContent() { - doSample(); -} - -void RegionSamplingThread::notifySamplingOffset() { - doSample(); +void RegionSamplingThread::onCompositionComplete( + std::optional samplingDeadline) { + doSample(samplingDeadline); } -void RegionSamplingThread::doSample() { +void RegionSamplingThread::doSample( + std::optional samplingDeadline) { std::lock_guard lock(mThreadControlMutex); - auto now = std::chrono::nanoseconds(systemTime(SYSTEM_TIME_MONOTONIC)); - if (lastSampleTime + mTunables.mSamplingPeriod > now) { + const auto now = std::chrono::steady_clock::now(); + if (mLastSampleTime + mTunables.mSamplingPeriod > now) { + // content changed, but we sampled not too long ago, so we need to sample some time in the + // future. ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::idleTimerWaiting)); - if (mDiscardedFrames == 0) mDiscardedFrames++; + mSampleRequestTime = now; return; } - if (mDiscardedFrames < maxRegionSamplingSkips) { + if (!mSampleRequestTime.has_value() || now - *mSampleRequestTime < maxRegionSamplingDelay) { // If there is relatively little time left for surfaceflinger // until the next vsync deadline, defer this sampling work // to a later frame, when hopefully there will be more time. - const DisplayStatInfo stats = mScheduler.getDisplayStatInfo(systemTime()); - if (std::chrono::nanoseconds(stats.vsyncTime) - now < timeForRegionSampling) { + if (samplingDeadline.has_value() && now + mTunables.mSamplingDuration > *samplingDeadline) { ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::waitForQuietFrame)); - mDiscardedFrames++; + mSampleRequestTime = mSampleRequestTime.value_or(now); return; } } ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::sample)); - mDiscardedFrames = 0; - lastSampleTime = now; + mSampleRequestTime.reset(); + mLastSampleTime = now; mIdleTimer.reset(); - mPhaseCallback->stopVsyncListener(); mSampleRequested = true; mCondition.notify_one(); diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h index 86632db490..2231853fcb 100644 --- a/services/surfaceflinger/RegionSamplingThread.h +++ b/services/surfaceflinger/RegionSamplingThread.h @@ -63,9 +63,8 @@ public: struct EnvironmentTimingTunables : TimingTunables { EnvironmentTimingTunables(); }; - explicit RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler, - const TimingTunables& tunables); - explicit RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler); + explicit RegionSamplingThread(SurfaceFlinger& flinger, const TimingTunables& tunables); + explicit RegionSamplingThread(SurfaceFlinger& flinger); ~RegionSamplingThread(); @@ -76,12 +75,11 @@ public: // Remove the listener to stop receiving median luma notifications. void removeListener(const sp& listener); - // Notifies sampling engine that new content is available. This will trigger a sampling - // pass at some point in the future. - void notifyNewContent(); - - // Notifies the sampling engine that it has a good timing window in which to sample. - void notifySamplingOffset(); + // Notifies sampling engine that composition is done and new content is + // available, and the deadline for the sampling work on the main thread to + // be completed without eating the budget of another frame. + void onCompositionComplete( + std::optional samplingDeadline); private: struct Descriptor { @@ -99,7 +97,7 @@ private: const sp& buffer, const Point& leftTop, const std::vector& descriptors, uint32_t orientation); - void doSample(); + void doSample(std::optional samplingDeadline); void binderDied(const wp& who) override; void checkForStaleLuma(); @@ -107,20 +105,18 @@ private: void threadMain(); SurfaceFlinger& mFlinger; - Scheduler& mScheduler; const TimingTunables mTunables; scheduler::OneShotTimer mIdleTimer; - std::unique_ptr const mPhaseCallback; - std::thread mThread; std::mutex mThreadControlMutex; std::condition_variable_any mCondition; bool mRunning GUARDED_BY(mThreadControlMutex) = true; bool mSampleRequested GUARDED_BY(mThreadControlMutex) = false; - uint32_t mDiscardedFrames GUARDED_BY(mThreadControlMutex) = 0; - std::chrono::nanoseconds lastSampleTime GUARDED_BY(mThreadControlMutex); + std::optional mSampleRequestTime + GUARDED_BY(mThreadControlMutex); + std::chrono::steady_clock::time_point mLastSampleTime GUARDED_BY(mThreadControlMutex); std::mutex mSamplingMutex; std::unordered_map, Descriptor, WpHash> mDescriptors GUARDED_BY(mSamplingMutex); diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index 7ff0ddfab4..4d51125156 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -23,7 +23,6 @@ #include #include -#include #include "EventThread.h" #include "FrameTimeline.h" @@ -33,27 +32,32 @@ namespace android::impl { void MessageQueue::Handler::dispatchRefresh() { - if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) { + if ((mEventMask.fetch_or(eventMaskRefresh) & eventMaskRefresh) == 0) { mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH)); } } void MessageQueue::Handler::dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp) { - if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) { + if ((mEventMask.fetch_or(eventMaskInvalidate) & eventMaskInvalidate) == 0) { mVsyncId = vsyncId; mExpectedVSyncTime = expectedVSyncTimestamp; mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE)); } } +bool MessageQueue::Handler::invalidatePending() { + constexpr auto pendingMask = eventMaskInvalidate | eventMaskRefresh; + return (mEventMask.load() & pendingMask) != 0; +} + void MessageQueue::Handler::handleMessage(const Message& message) { switch (message.what) { case INVALIDATE: - android_atomic_and(~eventMaskInvalidate, &mEventMask); + mEventMask.fetch_and(~eventMaskInvalidate); mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime); break; case REFRESH: - android_atomic_and(~eventMaskRefresh, &mEventMask); + mEventMask.fetch_and(~eventMaskRefresh); mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime); break; } @@ -106,7 +110,7 @@ void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, ns { std::lock_guard lock(mVsync.mutex); mVsync.lastCallbackTime = std::chrono::nanoseconds(vsyncTime); - mVsync.mScheduled = false; + mVsync.scheduled = false; } mHandler->dispatchInvalidate(mVsync.tokenManager->generateTokenForPredictions( {targetWakeupTime, readyTime, vsyncTime}), @@ -131,9 +135,10 @@ void MessageQueue::setDuration(std::chrono::nanoseconds workDuration) { ATRACE_CALL(); std::lock_guard lock(mVsync.mutex); mVsync.workDuration = workDuration; - if (mVsync.mScheduled) { - mVsync.registration->schedule({mVsync.workDuration.get().count(), /*readyDuration=*/0, - mVsync.lastCallbackTime.count()}); + if (mVsync.scheduled) { + mVsync.expectedWakeupTime = mVsync.registration->schedule( + {mVsync.workDuration.get().count(), + /*readyDuration=*/0, mVsync.lastCallbackTime.count()}); } } @@ -176,10 +181,11 @@ void MessageQueue::invalidate() { } std::lock_guard lock(mVsync.mutex); - mVsync.mScheduled = true; - mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(), - .readyDuration = 0, - .earliestVsync = mVsync.lastCallbackTime.count()}); + mVsync.scheduled = true; + mVsync.expectedWakeupTime = + mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(), + .readyDuration = 0, + .earliestVsync = mVsync.lastCallbackTime.count()}); } void MessageQueue::refresh() { @@ -200,4 +206,19 @@ void MessageQueue::injectorCallback() { } } +std::optional MessageQueue::nextExpectedInvalidate() { + if (mHandler->invalidatePending()) { + return std::chrono::steady_clock::now(); + } + + std::lock_guard lock(mVsync.mutex); + if (mVsync.scheduled) { + LOG_ALWAYS_FATAL_IF(!mVsync.expectedWakeupTime.has_value(), "callback was never scheduled"); + const auto expectedWakeupTime = std::chrono::nanoseconds(*mVsync.expectedWakeupTime); + return std::optional(expectedWakeupTime); + } + + return std::nullopt; +} + } // namespace android::impl diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h index 2934af047c..58ce9b9a2f 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.h +++ b/services/surfaceflinger/Scheduler/MessageQueue.h @@ -72,6 +72,7 @@ public: virtual void postMessage(sp&&) = 0; virtual void invalidate() = 0; virtual void refresh() = 0; + virtual std::optional nextExpectedInvalidate() = 0; }; // --------------------------------------------------------------------------- @@ -81,9 +82,13 @@ namespace impl { class MessageQueue : public android::MessageQueue { protected: class Handler : public MessageHandler { - enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 }; + enum : uint32_t { + eventMaskInvalidate = 0x1, + eventMaskRefresh = 0x2, + eventMaskTransaction = 0x4 + }; MessageQueue& mQueue; - int32_t mEventMask; + std::atomic mEventMask; std::atomic mVsyncId; std::atomic mExpectedVSyncTime; @@ -92,6 +97,7 @@ protected: void handleMessage(const Message& message) override; virtual void dispatchRefresh(); virtual void dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp); + virtual bool invalidatePending(); }; friend class Handler; @@ -107,7 +113,8 @@ protected: TracedOrdinal workDuration GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)}; std::chrono::nanoseconds lastCallbackTime GUARDED_BY(mutex) = std::chrono::nanoseconds{0}; - bool mScheduled GUARDED_BY(mutex) = false; + bool scheduled GUARDED_BY(mutex) = false; + std::optional expectedWakeupTime GUARDED_BY(mutex); TracedOrdinal value = {"VSYNC-sf", 0}; }; @@ -141,6 +148,8 @@ public: // sends REFRESH message at next VSYNC void refresh() override; + + std::optional nextExpectedInvalidate() override; }; } // namespace impl diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 267dd6d9d0..41aacc0ab7 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1909,6 +1909,7 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT mRefreshPending = true; onMessageRefresh(); } + notifyRegionSamplingThread(); } bool SurfaceFlinger::handleMessageTransaction() { @@ -2311,10 +2312,6 @@ void SurfaceFlinger::postComposition() { } } - if (mLumaSampling && mRegionSamplingThread) { - mRegionSamplingThread->notifyNewContent(); - } - // Even though ATRACE_INT64 already checks if tracing is enabled, it doesn't prevent the // side-effect of getTotalSize(), so we check that again here if (ATRACE_ENABLED()) { @@ -3067,8 +3064,7 @@ void SurfaceFlinger::initScheduler(const DisplayDeviceState& displayState) { configs.late.sfWorkDuration); mRegionSamplingThread = - new RegionSamplingThread(*this, *mScheduler, - RegionSamplingThread::EnvironmentTimingTunables()); + new RegionSamplingThread(*this, RegionSamplingThread::EnvironmentTimingTunables()); mFpsReporter = new FpsReporter(*mFrameTimeline, *this); // Dispatch a mode change request for the primary display on scheduler // initialization, so that the EventThreads always contain a reference to a @@ -6752,6 +6748,19 @@ sp SurfaceFlinger::handleLayerCreatedLocked(const sp& handle, bo return layer; } + +void SurfaceFlinger::scheduleRegionSamplingThread() { + static_cast(schedule([&] { notifyRegionSamplingThread(); })); +} + +void SurfaceFlinger::notifyRegionSamplingThread() { + if (!mLumaSampling || !mRegionSamplingThread) { + return; + } + + mRegionSamplingThread->onCompositionComplete(mEventQueue->nextExpectedInvalidate()); +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index cd20bd1c50..ea40cb510e 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1429,6 +1429,9 @@ private: REQUIRES(mStateLock); std::atomic mDefaultDisplayTransformHint; + + void scheduleRegionSamplingThread(); + void notifyRegionSamplingThread(); }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp index 18ebbab09a..dbd51fed78 100644 --- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp @@ -104,8 +104,12 @@ TEST_F(MessageQueueTest, invalidate) { const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(), .readyDuration = 0, .earliestVsync = 0}; - EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(0)); + EXPECT_FALSE(mEventQueue.nextExpectedInvalidate().has_value()); + + EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate()); + EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value()); + EXPECT_EQ(1234, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count()); } TEST_F(MessageQueueTest, invalidateTwice) { @@ -114,11 +118,15 @@ TEST_F(MessageQueueTest, invalidateTwice) { .readyDuration = 0, .earliestVsync = 0}; - EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(0)); + EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate()); + EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value()); + EXPECT_EQ(1234, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count()); - EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(0)); + EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(4567)); EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate()); + EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value()); + EXPECT_EQ(4567, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count()); } TEST_F(MessageQueueTest, invalidateTwiceWithCallback) { @@ -127,8 +135,10 @@ TEST_F(MessageQueueTest, invalidateTwiceWithCallback) { .readyDuration = 0, .earliestVsync = 0}; - EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(0)); + EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate()); + EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value()); + EXPECT_EQ(1234, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count()); const auto startTime = 100; const auto endTime = startTime + mDuration.count(); @@ -141,6 +151,8 @@ TEST_F(MessageQueueTest, invalidateTwiceWithCallback) { EXPECT_CALL(*mHandler, dispatchInvalidate(vsyncId, presentTime)).Times(1); EXPECT_NO_FATAL_FAILURE(mEventQueue.triggerVsyncCallback(presentTime, startTime, endTime)); + EXPECT_FALSE(mEventQueue.nextExpectedInvalidate().has_value()); + const auto timingAfterCallback = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(), .readyDuration = 0, diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h index 453c93a083..0e7b320787 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h +++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h @@ -39,6 +39,7 @@ public: void(scheduler::VSyncDispatch&, frametimeline::TokenManager&, std::chrono::nanoseconds)); MOCK_METHOD1(setDuration, void(std::chrono::nanoseconds workDuration)); + MOCK_METHOD0(nextExpectedInvalidate, std::optional()); }; } // namespace android::mock -- cgit v1.2.3-59-g8ed1b From a8f66857922d6af72782ebb863f79e077473e64f Mon Sep 17 00:00:00 2001 From: Huihong Luo Date: Fri, 2 Jul 2021 00:22:38 -0700 Subject: Fix color sampling for landscape Region sampling listener accepts coordinates already in the correct orientation, no additional transforms are needed. Bug: 178777512 Test: download Google I/O 2019 app, check system gesture navigation bar color Change-Id: I73f78a2a8390beb29b7ab33b2bed2b0326d367b1 --- services/surfaceflinger/RegionSamplingThread.cpp | 27 +++--------------------- 1 file changed, 3 insertions(+), 24 deletions(-) (limited to 'services/surfaceflinger/RegionSamplingThread.cpp') diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 653aca6cde..aa2fec56ad 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -287,33 +287,12 @@ void RegionSamplingThread::captureSample() { descriptors.emplace_back(descriptor); } - auto dx = 0; - auto dy = 0; - switch (orientation) { - case ui::Transform::ROT_90: - dx = displaySize.getWidth(); - break; - case ui::Transform::ROT_180: - dx = displaySize.getWidth(); - dy = displaySize.getHeight(); - break; - case ui::Transform::ROT_270: - dy = displaySize.getHeight(); - break; - default: - break; - } - - ui::Transform t(orientation); - auto screencapRegion = t.transform(sampleRegion); - screencapRegion = screencapRegion.translate(dx, dy); - const Rect sampledBounds = sampleRegion.bounds(); + constexpr bool kUseIdentityTransform = false; SurfaceFlinger::RenderAreaFuture renderAreaFuture = ftl::defer([=] { - return DisplayRenderArea::create(displayWeak, screencapRegion.bounds(), - sampledBounds.getSize(), ui::Dataspace::V0_SRGB, - orientation); + return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(), + ui::Dataspace::V0_SRGB, kUseIdentityTransform); }); std::unordered_set, SpHash> listeners; -- cgit v1.2.3-59-g8ed1b