From 2ec5391acfc340c2e195d573cf5a078ff0f280d2 Mon Sep 17 00:00:00 2001 From: John Reck Date: Tue, 7 Jul 2020 16:53:55 -0700 Subject: Remove obsolete debug option This is dead code, stop maintaining it Fixes: 159912967 Test: builds Change-Id: Ia453eaf895554adbb2fa9c11c2bc8609e1037ea5 --- services/surfaceflinger/BufferLayer.cpp | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index f0b0200bc5..cf60b713ba 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -539,20 +539,6 @@ bool BufferLayer::isProtected() const { return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED); } -bool BufferLayer::latchUnsignaledBuffers() { - static bool propertyLoaded = false; - static bool latch = false; - static std::mutex mutex; - std::lock_guard lock(mutex); - if (!propertyLoaded) { - char value[PROPERTY_VALUE_MAX] = {}; - property_get("debug.sf.latch_unsignaled", value, "0"); - latch = atoi(value); - propertyLoaded = true; - } - return latch; -} - // h/w composer set-up bool BufferLayer::allTransactionsSignaled(nsecs_t expectedPresentTime) { const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime); -- cgit v1.2.3-59-g8ed1b From 0f10d0db65310f0734394c3809d78a4ee33ea364 Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Thu, 6 Aug 2020 20:04:06 +0200 Subject: Revert^2 "[SF] Introduce VirtualDisplayId" This change introduces a new class VirtualDisplayId which is inherited by HwcVirtualDisplayId and GpuVirtualDisplayId. HwcVirtualDisplayId replaces the current ids assigned to virtual displays backed by HWC. GpuVirtualDisplayIds are random generated IDs assigned to non HWC virtual displays, which currently don't have IDs. This way all compositionengine/Display and DisplayDevice objects have a DisplayId. The logic for ID generation is encapsulated in DisplayIdGenerator.h. Bug: 162916145 Bug: 160679868 Bug: 137375833 Test: scrcpy on device Test: atest DisplayIdGeneratorTest Test: atest libsurfaceflinger_unittest Test: m WITH_TIDY=1 surfaceflinger Change-Id: I6e7247d18e3521978dfd8af2dc7b1d36ccaa7313 --- libs/ui/include/ui/DisplayId.h | 100 ++++++++++++- libs/ui/tests/Android.bp | 7 + libs/ui/tests/DisplayId_test.cpp | 66 +++++++++ services/surfaceflinger/BufferLayer.cpp | 2 +- .../include/compositionengine/Display.h | 4 +- .../compositionengine/DisplayCreationArgs.h | 11 ++ .../include/compositionengine/impl/Display.h | 8 +- .../include/compositionengine/mock/Display.h | 2 +- .../CompositionEngine/src/Display.cpp | 134 +++++++++-------- .../CompositionEngine/tests/DisplayTest.cpp | 54 ++++--- .../CompositionEngine/tests/MockHWComposer.h | 83 ++++++----- .../CompositionEngine/tests/RenderSurfaceTest.cpp | 4 +- services/surfaceflinger/DisplayDevice.cpp | 11 +- services/surfaceflinger/DisplayDevice.h | 11 +- .../DisplayHardware/FramebufferSurface.cpp | 2 +- .../DisplayHardware/FramebufferSurface.h | 5 +- services/surfaceflinger/DisplayHardware/HWC2.h | 22 ++- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 127 ++++++++-------- .../surfaceflinger/DisplayHardware/HWComposer.h | 160 ++++++++++----------- .../DisplayHardware/VirtualDisplaySurface.cpp | 36 ++--- .../DisplayHardware/VirtualDisplaySurface.h | 44 +++--- services/surfaceflinger/DisplayIdGenerator.h | 75 ++++++++++ services/surfaceflinger/SurfaceFlinger.cpp | 150 +++++++++---------- services/surfaceflinger/SurfaceFlinger.h | 7 +- services/surfaceflinger/tests/unittests/Android.bp | 1 + .../tests/unittests/DisplayIdGeneratorTest.cpp | 82 +++++++++++ .../tests/unittests/DisplayTransactionTest.cpp | 125 ++++++++++------ .../tests/unittests/TestableSurfaceFlinger.h | 20 ++- .../mock/DisplayHardware/MockComposer.cpp | 8 +- .../unittests/mock/DisplayHardware/MockComposer.h | 6 +- .../unittests/mock/DisplayHardware/MockDisplay.cpp | 8 +- .../unittests/mock/DisplayHardware/MockDisplay.h | 8 +- .../mock/DisplayHardware/MockPowerAdvisor.cpp | 8 +- .../mock/DisplayHardware/MockPowerAdvisor.h | 8 +- .../tests/unittests/mock/MockDisplayIdGenerator.h | 36 +++++ .../tests/unittests/mock/MockEventThread.cpp | 6 +- .../tests/unittests/mock/MockEventThread.h | 6 +- .../tests/unittests/mock/MockFrameTracer.cpp | 6 +- .../tests/unittests/mock/MockFrameTracer.h | 6 +- .../unittests/mock/MockSurfaceInterceptor.cpp | 6 +- .../tests/unittests/mock/MockSurfaceInterceptor.h | 6 +- .../tests/unittests/mock/MockTimeStats.cpp | 6 +- .../tests/unittests/mock/MockTimeStats.h | 6 +- .../tests/unittests/mock/MockVSyncTracker.cpp | 8 +- .../tests/unittests/mock/MockVsyncController.h | 6 +- 45 files changed, 936 insertions(+), 561 deletions(-) create mode 100644 libs/ui/tests/DisplayId_test.cpp create mode 100644 services/surfaceflinger/DisplayIdGenerator.h create mode 100644 services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp create mode 100644 services/surfaceflinger/tests/unittests/mock/MockDisplayIdGenerator.h (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h index 9eb54836af..f196ab901a 100644 --- a/libs/ui/include/ui/DisplayId.h +++ b/libs/ui/include/ui/DisplayId.h @@ -17,13 +17,20 @@ #pragma once #include -#include +#include #include namespace android { // ID of a physical or a virtual display. This class acts as a type safe wrapper around uint64_t. +// The encoding of the ID is type-specific for bits 0 to 61. struct DisplayId { + // Flag indicating that the display is virtual. + static constexpr uint64_t FLAG_VIRTUAL = 1ULL << 63; + + // Flag indicating that the ID is stable across reboots. + static constexpr uint64_t FLAG_STABLE = 1ULL << 62; + // TODO(b/162612135) Remove default constructor DisplayId() = default; constexpr DisplayId(const DisplayId&) = default; @@ -51,8 +58,12 @@ inline std::string to_string(DisplayId displayId) { // DisplayId of a physical display, such as the internal display or externally connected display. struct PhysicalDisplayId : DisplayId { - // Flag indicating that the ID is stable across reboots. - static constexpr uint64_t FLAG_STABLE = 1ULL << 62; + static constexpr std::optional tryCast(DisplayId id) { + if (id.value & FLAG_VIRTUAL) { + return std::nullopt; + } + return {PhysicalDisplayId(id)}; + } // Returns a stable ID based on EDID information. static constexpr PhysicalDisplayId fromEdid(uint8_t port, uint16_t manufacturerId, @@ -69,8 +80,8 @@ struct PhysicalDisplayId : DisplayId { // TODO(b/162612135) Remove default constructor PhysicalDisplayId() = default; + // TODO(b/162612135) Remove constructor explicit constexpr PhysicalDisplayId(uint64_t id) : DisplayId(id) {} - explicit constexpr PhysicalDisplayId(DisplayId other) : DisplayId(other.value) {} constexpr uint16_t getManufacturerId() const { return static_cast(value >> 40); } @@ -81,10 +92,82 @@ private: uint32_t modelHash) : DisplayId(flags | (static_cast(manufacturerId) << 40) | (static_cast(modelHash) << 8) | port) {} + + explicit constexpr PhysicalDisplayId(DisplayId other) : DisplayId(other) {} }; static_assert(sizeof(PhysicalDisplayId) == sizeof(uint64_t)); +struct VirtualDisplayId : DisplayId { + using BaseId = uint32_t; + // Flag indicating that this virtual display is backed by the GPU. + static constexpr uint64_t FLAG_GPU = 1ULL << 61; + + static constexpr std::optional tryCast(DisplayId id) { + if (id.value & FLAG_VIRTUAL) { + return {VirtualDisplayId(id)}; + } + return std::nullopt; + } + +protected: + constexpr VirtualDisplayId(uint64_t flags, BaseId baseId) + : DisplayId(DisplayId::FLAG_VIRTUAL | flags | baseId) {} + + explicit constexpr VirtualDisplayId(DisplayId other) : DisplayId(other) {} +}; + +struct HalVirtualDisplayId : VirtualDisplayId { + explicit constexpr HalVirtualDisplayId(BaseId baseId) : VirtualDisplayId(0, baseId) {} + + static constexpr std::optional tryCast(DisplayId id) { + if ((id.value & FLAG_VIRTUAL) && !(id.value & VirtualDisplayId::FLAG_GPU)) { + return {HalVirtualDisplayId(id)}; + } + return std::nullopt; + } + +private: + explicit constexpr HalVirtualDisplayId(DisplayId other) : VirtualDisplayId(other) {} +}; + +struct GpuVirtualDisplayId : VirtualDisplayId { + explicit constexpr GpuVirtualDisplayId(BaseId baseId) + : VirtualDisplayId(VirtualDisplayId::FLAG_GPU, baseId) {} + + static constexpr std::optional tryCast(DisplayId id) { + if ((id.value & FLAG_VIRTUAL) && (id.value & VirtualDisplayId::FLAG_GPU)) { + return {GpuVirtualDisplayId(id)}; + } + return std::nullopt; + } + +private: + explicit constexpr GpuVirtualDisplayId(DisplayId other) : VirtualDisplayId(other) {} +}; + +// HalDisplayId is the ID of a display which is managed by HWC. +// PhysicalDisplayId and HalVirtualDisplayId are implicitly convertible to HalDisplayId. +struct HalDisplayId : DisplayId { + constexpr HalDisplayId(HalVirtualDisplayId other) : DisplayId(other) {} + constexpr HalDisplayId(PhysicalDisplayId other) : DisplayId(other) {} + + static constexpr std::optional tryCast(DisplayId id) { + if (GpuVirtualDisplayId::tryCast(id)) { + return std::nullopt; + } + return {HalDisplayId(id)}; + } + +private: + explicit constexpr HalDisplayId(DisplayId other) : DisplayId(other) {} +}; + +static_assert(sizeof(VirtualDisplayId) == sizeof(uint64_t)); +static_assert(sizeof(HalVirtualDisplayId) == sizeof(uint64_t)); +static_assert(sizeof(GpuVirtualDisplayId) == sizeof(uint64_t)); +static_assert(sizeof(HalDisplayId) == sizeof(uint64_t)); + } // namespace android namespace std { @@ -99,4 +182,13 @@ struct hash { template <> struct hash : hash {}; +template <> +struct hash : hash {}; + +template <> +struct hash : hash {}; + +template <> +struct hash : hash {}; + } // namespace std diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 032dd4c4ef..d005ce8e23 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -28,6 +28,13 @@ cc_test { cflags: ["-Wall", "-Werror"], } +cc_test { + name: "DisplayId_test", + shared_libs: ["libui"], + srcs: ["DisplayId_test.cpp"], + cflags: ["-Wall", "-Werror"], +} + cc_test { name: "FlattenableHelpers_test", shared_libs: ["libui"], diff --git a/libs/ui/tests/DisplayId_test.cpp b/libs/ui/tests/DisplayId_test.cpp new file mode 100644 index 0000000000..1d908b8ef1 --- /dev/null +++ b/libs/ui/tests/DisplayId_test.cpp @@ -0,0 +1,66 @@ +/* + * 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 + +namespace android::ui { + +TEST(DisplayIdTest, createPhysicalIdFromEdid) { + constexpr uint8_t port = 1; + constexpr uint16_t manufacturerId = 13; + constexpr uint32_t modelHash = 42; + PhysicalDisplayId id = PhysicalDisplayId::fromEdid(port, manufacturerId, modelHash); + EXPECT_EQ(port, id.getPort()); + EXPECT_EQ(manufacturerId, id.getManufacturerId()); + EXPECT_FALSE(VirtualDisplayId::tryCast(id)); + EXPECT_FALSE(HalVirtualDisplayId::tryCast(id)); + EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); + EXPECT_TRUE(PhysicalDisplayId::tryCast(id)); + EXPECT_TRUE(HalDisplayId::tryCast(id)); +} + +TEST(DisplayIdTest, createPhysicalIdFromPort) { + constexpr uint8_t port = 3; + PhysicalDisplayId id = PhysicalDisplayId::fromPort(port); + EXPECT_EQ(port, id.getPort()); + EXPECT_FALSE(VirtualDisplayId::tryCast(id)); + EXPECT_FALSE(HalVirtualDisplayId::tryCast(id)); + EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); + EXPECT_TRUE(PhysicalDisplayId::tryCast(id)); + EXPECT_TRUE(HalDisplayId::tryCast(id)); +} + +TEST(DisplayIdTest, createGpuVirtualId) { + GpuVirtualDisplayId id(42); + EXPECT_TRUE(VirtualDisplayId::tryCast(id)); + EXPECT_TRUE(GpuVirtualDisplayId::tryCast(id)); + EXPECT_FALSE(HalVirtualDisplayId::tryCast(id)); + EXPECT_FALSE(PhysicalDisplayId::tryCast(id)); + EXPECT_FALSE(HalDisplayId::tryCast(id)); +} + +TEST(DisplayIdTest, createHalVirtualId) { + HalVirtualDisplayId id(42); + EXPECT_TRUE(VirtualDisplayId::tryCast(id)); + EXPECT_TRUE(HalVirtualDisplayId::tryCast(id)); + EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); + EXPECT_FALSE(PhysicalDisplayId::tryCast(id)); + EXPECT_TRUE(HalDisplayId::tryCast(id)); +} + +} // namespace android::ui diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index cf60b713ba..c77298e161 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -366,7 +366,7 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, mFrameTracker.setActualPresentFence(std::shared_ptr(presentFence)); } else if (!display) { // Do nothing. - } else if (const auto displayId = display->getId(); + } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId()); displayId && mFlinger->getHwComposer().isConnected(*displayId)) { // The HWC doesn't support present fences, so use the refresh // timestamp instead. diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h index a38d1f3c99..01dd5343b2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h @@ -34,8 +34,8 @@ struct DisplayColorProfileCreationArgs; */ class Display : public virtual Output { public: - // Gets the HWC DisplayId for the display if there is one - virtual const std::optional& getId() const = 0; + // Gets the DisplayId for the display + virtual DisplayId getId() const = 0; // True if the display is secure virtual bool isSecure() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h index 6bc677d432..95ba9f0429 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h @@ -20,12 +20,14 @@ #include #include +#include #include #include #include #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/PowerAdvisor.h" +#include "DisplayIdGenerator.h" namespace android::compositionengine { @@ -65,6 +67,9 @@ struct DisplayCreationArgs { // Debugging. Human readable name for the display. std::string name; + + // Generator for IDs of virtual displays, which are backed by the GPU. + DisplayIdGenerator* gpuVirtualDisplayIdGenerator; }; /** @@ -95,6 +100,12 @@ public: return *this; } + DisplayCreationArgsBuilder& setGpuVirtualDisplayIdGenerator( + DisplayIdGenerator& generator) { + mArgs.gpuVirtualDisplayIdGenerator = &generator; + return *this; + } + DisplayCreationArgsBuilder& setIsSecure(bool isSecure) { mArgs.isSecure = isSecure; return *this; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index 7a4f7383d0..54e91ae6be 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -57,7 +57,7 @@ public: void finishFrame(const CompositionRefreshArgs&) override; // compositionengine::Display overrides - const std::optional& getId() const override; + DisplayId getId() const override; bool isSecure() const override; bool isVirtual() const override; void disconnect() override; @@ -85,12 +85,14 @@ public: std::unique_ptr createOutputLayer(const sp&) const; // Testing - void setDisplayIdForTesting(std::optional displayId); + void setDisplayIdForTesting(DisplayId displayId); private: bool mIsVirtual = false; - std::optional mId; + bool mIsDisconnected = false; + DisplayId mId; Hwc2::PowerAdvisor* mPowerAdvisor = nullptr; + DisplayIdGenerator* mGpuVirtualDisplayIdGenerator; }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h index 3a4c70fd64..08a8b84306 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h @@ -32,7 +32,7 @@ public: Display(); virtual ~Display(); - MOCK_CONST_METHOD0(getId, const std::optional&()); + MOCK_CONST_METHOD0(getId, DisplayId()); MOCK_CONST_METHOD0(isSecure, bool()); MOCK_CONST_METHOD0(isVirtual, bool()); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 54598619e9..0b0b8d5e9c 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -51,19 +51,26 @@ Display::~Display() = default; void Display::setConfiguration(const compositionengine::DisplayCreationArgs& args) { mIsVirtual = !args.physical; - mId = args.physical ? std::make_optional(args.physical->id) : std::nullopt; mPowerAdvisor = args.powerAdvisor; - editState().isSecure = args.isSecure; editState().displaySpace.bounds = Rect(args.pixels); - setLayerStackFilter(args.layerStackId, - args.physical ? args.physical->type == DisplayConnectionType::Internal - : false); + args.physical && args.physical->type == DisplayConnectionType::Internal); setName(args.name); + mGpuVirtualDisplayIdGenerator = args.gpuVirtualDisplayIdGenerator; - if (!args.physical && args.useHwcVirtualDisplays) { - mId = maybeAllocateDisplayIdForVirtualDisplay(args.pixels, args.pixelFormat); + if (args.physical) { + mId = args.physical->id; + } else { + std::optional id; + if (args.useHwcVirtualDisplays) { + id = maybeAllocateDisplayIdForVirtualDisplay(args.pixels, args.pixelFormat); + } + if (!id) { + id = mGpuVirtualDisplayIdGenerator->nextId(); + } + LOG_ALWAYS_FATAL_IF(!id, "Failed to generate display ID"); + mId = *id; } } @@ -78,7 +85,7 @@ bool Display::isValid() const { return Output::isValid() && mPowerAdvisor; } -const std::optional& Display::getId() const { +DisplayId Display::getId() const { return mId; } @@ -94,31 +101,36 @@ std::optional Display::getDisplayId() const { return mId; } -void Display::setDisplayIdForTesting(std::optional displayId) { +void Display::setDisplayIdForTesting(DisplayId displayId) { mId = displayId; } void Display::disconnect() { - if (!mId) { + if (mIsDisconnected) { return; } - auto& hwc = getCompositionEngine().getHwComposer(); - hwc.disconnectDisplay(*mId); - mId.reset(); + mIsDisconnected = true; + if (const auto id = GpuVirtualDisplayId::tryCast(mId)) { + mGpuVirtualDisplayIdGenerator->markUnused(*id); + return; + } + const auto halDisplayId = HalDisplayId::tryCast(mId); + LOG_FATAL_IF(!halDisplayId); + getCompositionEngine().getHwComposer().disconnectDisplay(*halDisplayId); } void Display::setColorTransform(const compositionengine::CompositionRefreshArgs& args) { Output::setColorTransform(args); - - if (!mId || CC_LIKELY(!args.colorTransformMatrix)) { + const auto halDisplayId = HalDisplayId::tryCast(mId); + if (mIsDisconnected || !halDisplayId || CC_LIKELY(!args.colorTransformMatrix)) { return; } auto& hwc = getCompositionEngine().getHwComposer(); - status_t result = hwc.setColorTransform(*mId, *args.colorTransformMatrix); + status_t result = hwc.setColorTransform(*halDisplayId, *args.colorTransformMatrix); ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display \"%s\": %d", - mId ? to_string(*mId).c_str() : "", result); + to_string(mId).c_str(), result); } void Display::setColorProfile(const ColorProfile& colorProfile) { @@ -140,8 +152,10 @@ void Display::setColorProfile(const ColorProfile& colorProfile) { Output::setColorProfile(colorProfile); - auto& hwc = getCompositionEngine().getHwComposer(); - hwc.setActiveColorMode(*mId, colorProfile.mode, colorProfile.renderIntent); + const auto physicalId = PhysicalDisplayId::tryCast(mId); + LOG_FATAL_IF(!physicalId); + getCompositionEngine().getHwComposer().setActiveColorMode(*physicalId, colorProfile.mode, + colorProfile.renderIntent); } void Display::dump(std::string& out) const { @@ -150,14 +164,8 @@ void Display::dump(std::string& out) const { StringAppendF(&out, " Composition Display State: [\"%s\"]", getName().c_str()); out.append("\n "); - dumpVal(out, "isVirtual", mIsVirtual); - if (mId) { - dumpVal(out, "hwcId", to_string(*mId)); - } else { - StringAppendF(&out, "no hwcId, "); - } - + dumpVal(out, "DisplayId", to_string(mId)); out.append("\n"); Output::dumpBase(out); @@ -178,31 +186,33 @@ void Display::createClientCompositionCache(uint32_t cacheSize) { std::unique_ptr Display::createOutputLayer( const sp& layerFE) const { - auto result = impl::createOutputLayer(*this, layerFE); + auto outputLayer = impl::createOutputLayer(*this, layerFE); - if (result && mId) { + if (const auto halDisplayId = HalDisplayId::tryCast(mId); + outputLayer && !mIsDisconnected && halDisplayId) { auto& hwc = getCompositionEngine().getHwComposer(); - auto displayId = *mId; // Note: For the moment we ensure it is safe to take a reference to the // HWComposer implementation by destroying all the OutputLayers (and // hence the HWC2::Layers they own) before setting a new HWComposer. See // for example SurfaceFlinger::updateVrFlinger(). // TODO(b/121291683): Make this safer. - auto hwcLayer = std::shared_ptr(hwc.createLayer(displayId), - [&hwc, displayId](HWC2::Layer* layer) { - hwc.destroyLayer(displayId, layer); - }); + auto hwcLayer = + std::shared_ptr(hwc.createLayer(*halDisplayId), + [&hwc, id = *halDisplayId](HWC2::Layer* layer) { + hwc.destroyLayer(id, layer); + }); ALOGE_IF(!hwcLayer, "Failed to create a HWC layer for a HWC supported display %s", getName().c_str()); - result->setHwcLayer(std::move(hwcLayer)); + outputLayer->setHwcLayer(std::move(hwcLayer)); } - return result; + return outputLayer; } void Display::setReleasedLayers(const compositionengine::CompositionRefreshArgs& refreshArgs) { Output::setReleasedLayers(refreshArgs); - if (!mId || refreshArgs.layersWithQueuedFrames.empty()) { + if (mIsDisconnected || GpuVirtualDisplayId::tryCast(mId) || + refreshArgs.layersWithQueuedFrames.empty()) { return; } @@ -238,19 +248,25 @@ void Display::chooseCompositionStrategy() { ATRACE_CALL(); ALOGV(__FUNCTION__); + if (mIsDisconnected) { + return; + } + // Default to the base settings -- client composition only. Output::chooseCompositionStrategy(); - // If we don't have a HWC display, then we are done - if (!mId) { + // If we don't have a HWC display, then we are done. + const auto halDisplayId = HalDisplayId::tryCast(mId); + if (!halDisplayId) { return; } // Get any composition changes requested by the HWC device, and apply them. std::optional changes; auto& hwc = getCompositionEngine().getHwComposer(); - if (status_t result = hwc.getDeviceCompositionChanges(*mId, anyLayersRequireClientComposition(), - &changes); + if (status_t result = + hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(), + &changes); result != NO_ERROR) { ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result, strerror(-result)); @@ -271,8 +287,12 @@ void Display::chooseCompositionStrategy() { bool Display::getSkipColorTransform() const { const auto& hwc = getCompositionEngine().getHwComposer(); - return mId ? hwc.hasDisplayCapability(*mId, hal::DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM) - : hwc.hasCapability(hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM); + if (const auto halDisplayId = HalDisplayId::tryCast(mId)) { + return hwc.hasDisplayCapability(*halDisplayId, + hal::DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM); + } + + return hwc.hasCapability(hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM); } bool Display::anyLayersRequireClientComposition() const { @@ -339,16 +359,17 @@ void Display::applyClientTargetRequests(const ClientTargetProperty& clientTarget } compositionengine::Output::FrameFences Display::presentAndGetFrameFences() { - auto result = impl::Output::presentAndGetFrameFences(); + auto fences = impl::Output::presentAndGetFrameFences(); - if (!mId) { - return result; + const auto halDisplayIdOpt = HalDisplayId::tryCast(mId); + if (mIsDisconnected || !halDisplayIdOpt) { + return fences; } auto& hwc = getCompositionEngine().getHwComposer(); - hwc.presentAndGetReleaseFences(*mId); + hwc.presentAndGetReleaseFences(*halDisplayIdOpt); - result.presentFence = hwc.getPresentFence(*mId); + fences.presentFence = hwc.getPresentFence(*halDisplayIdOpt); // TODO(b/121291683): Change HWComposer call to return entire map for (const auto* layer : getOutputLayersOrderedByZ()) { @@ -357,19 +378,19 @@ compositionengine::Output::FrameFences Display::presentAndGetFrameFences() { continue; } - result.layerFences.emplace(hwcLayer, hwc.getLayerReleaseFence(*mId, hwcLayer)); + fences.layerFences.emplace(hwcLayer, hwc.getLayerReleaseFence(*halDisplayIdOpt, hwcLayer)); } - hwc.clearReleaseFences(*mId); + hwc.clearReleaseFences(*halDisplayIdOpt); - return result; + return fences; } void Display::setExpensiveRenderingExpected(bool enabled) { Output::setExpensiveRenderingExpected(enabled); - if (mPowerAdvisor && mId) { - mPowerAdvisor->setExpensiveRenderingExpected(*mId, enabled); + if (mPowerAdvisor && !GpuVirtualDisplayId::tryCast(mId)) { + mPowerAdvisor->setExpensiveRenderingExpected(mId, enabled); } } @@ -378,11 +399,10 @@ void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refre // 1) It is being handled by hardware composer, which may need this to // keep its virtual display state machine in sync, or // 2) There is work to be done (the dirty region isn't empty) - if (!mId) { - if (getDirtyRegion(refreshArgs.repaintEverything).isEmpty()) { - ALOGV("Skipping display composition"); - return; - } + if (GpuVirtualDisplayId::tryCast(mId) && + getDirtyRegion(refreshArgs.repaintEverything).isEmpty()) { + ALOGV("Skipping display composition"); + return; } impl::Output::finishFrame(refreshArgs); diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 4519a9d871..6d01bf195b 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -176,6 +176,7 @@ struct DisplayTestCommon : public testing::Test { DisplayCreationArgs getDisplayCreationArgsForNonHWCVirtualDisplay() { return DisplayCreationArgsBuilder() .setUseHwcVirtualDisplays(false) + .setGpuVirtualDisplayIdGenerator(mGpuDisplayIdGenerator) .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) .setIsSecure(false) @@ -189,6 +190,7 @@ struct DisplayTestCommon : public testing::Test { StrictMock mRenderEngine; StrictMock mCompositionEngine; sp mNativeWindow = new StrictMock(); + RandomDisplayIdGenerator mGpuDisplayIdGenerator; }; struct PartialMockDisplayTestCommon : public DisplayTestCommon { @@ -245,7 +247,7 @@ TEST_F(DisplayCreationTest, createNonHwcVirtualDisplay) { getDisplayCreationArgsForNonHWCVirtualDisplay()); EXPECT_FALSE(display->isSecure()); EXPECT_TRUE(display->isVirtual()); - EXPECT_EQ(std::nullopt, display->getId()); + EXPECT_TRUE(GpuVirtualDisplayId::tryCast(display->getId())); } /* @@ -332,6 +334,7 @@ TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfHwcAll mDisplay->setConfiguration( DisplayCreationArgsBuilder() .setUseHwcVirtualDisplays(true) + .setGpuVirtualDisplayIdGenerator(mGpuDisplayIdGenerator) .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) .setIsSecure(false) @@ -340,7 +343,7 @@ TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfHwcAll .setName(getDisplayNameFromCurrentTest()) .build()); - EXPECT_EQ(std::nullopt, mDisplay->getId()); + EXPECT_TRUE(GpuVirtualDisplayId::tryCast(mDisplay->getId())); EXPECT_FALSE(mDisplay->isSecure()); EXPECT_TRUE(mDisplay->isVirtual()); EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); @@ -352,6 +355,7 @@ TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfShould mDisplay->setConfiguration( DisplayCreationArgsBuilder() .setUseHwcVirtualDisplays(false) + .setGpuVirtualDisplayIdGenerator(mGpuDisplayIdGenerator) .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) .setIsSecure(false) @@ -360,7 +364,7 @@ TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfShould .setName(getDisplayNameFromCurrentTest()) .build()); - EXPECT_EQ(std::nullopt, mDisplay->getId()); + EXPECT_TRUE(GpuVirtualDisplayId::tryCast(mDisplay->getId())); EXPECT_FALSE(mDisplay->isSecure()); EXPECT_TRUE(mDisplay->isVirtual()); EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); @@ -375,16 +379,13 @@ TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfShould using DisplayDisconnectTest = PartialMockDisplayTestCommon; TEST_F(DisplayDisconnectTest, disconnectsDisplay) { - // The first call to disconnect will disconnect the display with the HWC and - // set mHwcId to -1. - EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(1); + // The first call to disconnect will disconnect the display with the HWC. + EXPECT_CALL(mHwComposer, disconnectDisplay(HalDisplayId(DEFAULT_DISPLAY_ID))).Times(1); mDisplay->disconnect(); - EXPECT_FALSE(mDisplay->getId()); // Subsequent calls will do nothing, - EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(0); + EXPECT_CALL(mHwComposer, disconnectDisplay(HalDisplayId(DEFAULT_DISPLAY_ID))).Times(0); mDisplay->disconnect(); - EXPECT_FALSE(mDisplay->getId()); } /* @@ -402,7 +403,8 @@ TEST_F(DisplaySetColorTransformTest, setsTransform) { // Identity matrix sets an identity state value const mat4 kIdentity; - EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, kIdentity)).Times(1); + EXPECT_CALL(mHwComposer, setColorTransform(HalDisplayId(DEFAULT_DISPLAY_ID), kIdentity)) + .Times(1); refreshArgs.colorTransformMatrix = kIdentity; mDisplay->setColorTransform(refreshArgs); @@ -410,7 +412,8 @@ TEST_F(DisplaySetColorTransformTest, setsTransform) { // Non-identity matrix sets a non-identity state value const mat4 kNonIdentity = mat4() * 2; - EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, kNonIdentity)).Times(1); + EXPECT_CALL(mHwComposer, setColorTransform(HalDisplayId(DEFAULT_DISPLAY_ID), kNonIdentity)) + .Times(1); refreshArgs.colorTransformMatrix = kNonIdentity; mDisplay->setColorTransform(refreshArgs); @@ -527,13 +530,14 @@ TEST_F(DisplayCreateOutputLayerTest, setsHwcLayer) { sp layerFE = new StrictMock(); StrictMock hwcLayer; - EXPECT_CALL(mHwComposer, createLayer(DEFAULT_DISPLAY_ID)).WillOnce(Return(&hwcLayer)); + EXPECT_CALL(mHwComposer, createLayer(HalDisplayId(DEFAULT_DISPLAY_ID))) + .WillOnce(Return(&hwcLayer)); auto outputLayer = mDisplay->createOutputLayer(layerFE); EXPECT_EQ(&hwcLayer, outputLayer->getHwcLayer()); - EXPECT_CALL(mHwComposer, destroyLayer(DEFAULT_DISPLAY_ID, &hwcLayer)); + EXPECT_CALL(mHwComposer, destroyLayer(HalDisplayId(DEFAULT_DISPLAY_ID), &hwcLayer)); outputLayer.reset(); } @@ -606,7 +610,7 @@ TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) { auto args = getDisplayCreationArgsForNonHWCVirtualDisplay(); std::shared_ptr nonHwcDisplay = createPartialMockDisplay(mCompositionEngine, args); - EXPECT_FALSE(nonHwcDisplay->getId()); + EXPECT_TRUE(GpuVirtualDisplayId::tryCast(nonHwcDisplay->getId())); nonHwcDisplay->chooseCompositionStrategy(); @@ -617,7 +621,8 @@ TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) { TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutOnHwcError) { EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()).WillOnce(Return(false)); - EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, false, _)) + EXPECT_CALL(mHwComposer, + getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), false, _)) .WillOnce(Return(INVALID_OPERATION)); mDisplay->chooseCompositionStrategy(); @@ -639,7 +644,7 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { .InSequence(s) .WillOnce(Return(false)); - EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _)) + EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _)) .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); @@ -669,7 +674,7 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { .InSequence(s) .WillOnce(Return(false)); - EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _)) + EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _)) .WillOnce(DoAll(SetArgPointee<2>(changes), Return(NO_ERROR))); EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1); EXPECT_CALL(*mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1); @@ -699,7 +704,7 @@ TEST_F(DisplayGetSkipColorTransformTest, checksCapabilityIfNonHwcDisplay) { TEST_F(DisplayGetSkipColorTransformTest, checksDisplayCapability) { EXPECT_CALL(mHwComposer, - hasDisplayCapability(DEFAULT_DISPLAY_ID, + hasDisplayCapability(HalDisplayId(DEFAULT_DISPLAY_ID), hal::DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM)) .WillOnce(Return(true)); EXPECT_TRUE(mDisplay->getSkipColorTransform()); @@ -857,13 +862,16 @@ TEST_F(DisplayPresentAndGetFrameFencesTest, returnsPresentAndLayerFences) { sp layer1Fence = new Fence(); sp layer2Fence = new Fence(); - EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(DEFAULT_DISPLAY_ID)).Times(1); - EXPECT_CALL(mHwComposer, getPresentFence(DEFAULT_DISPLAY_ID)).WillOnce(Return(presentFence)); - EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mLayer1.hwc2Layer)) + EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(HalDisplayId(DEFAULT_DISPLAY_ID))).Times(1); + EXPECT_CALL(mHwComposer, getPresentFence(HalDisplayId(DEFAULT_DISPLAY_ID))) + .WillOnce(Return(presentFence)); + EXPECT_CALL(mHwComposer, + getLayerReleaseFence(HalDisplayId(DEFAULT_DISPLAY_ID), &mLayer1.hwc2Layer)) .WillOnce(Return(layer1Fence)); - EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mLayer2.hwc2Layer)) + EXPECT_CALL(mHwComposer, + getLayerReleaseFence(HalDisplayId(DEFAULT_DISPLAY_ID), &mLayer2.hwc2Layer)) .WillOnce(Return(layer2Fence)); - EXPECT_CALL(mHwComposer, clearReleaseFences(DEFAULT_DISPLAY_ID)).Times(1); + EXPECT_CALL(mHwComposer, clearReleaseFences(HalDisplayId(DEFAULT_DISPLAY_ID))).Times(1); auto result = mDisplay->presentAndGetFrameFences(); diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index 1dd5df4770..b5cda685af 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -42,63 +42,68 @@ public: MOCK_CONST_METHOD3(getDisplayIdentificationData, bool(hal::HWDisplayId, uint8_t*, DisplayIdentificationData*)); MOCK_CONST_METHOD1(hasCapability, bool(hal::Capability)); - MOCK_CONST_METHOD2(hasDisplayCapability, bool(DisplayId, hal::DisplayCapability)); + MOCK_CONST_METHOD2(hasDisplayCapability, bool(HalDisplayId, hal::DisplayCapability)); MOCK_METHOD3(allocateVirtualDisplay, std::optional(uint32_t, uint32_t, ui::PixelFormat*)); MOCK_METHOD2(allocatePhysicalDisplay, void(hal::HWDisplayId, PhysicalDisplayId)); - MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId)); - MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*)); + MOCK_METHOD1(createLayer, HWC2::Layer*(HalDisplayId)); + MOCK_METHOD2(destroyLayer, void(HalDisplayId, HWC2::Layer*)); MOCK_METHOD3(getDeviceCompositionChanges, - status_t(DisplayId, bool, + status_t(HalDisplayId, bool, std::optional*)); MOCK_METHOD5(setClientTarget, - status_t(DisplayId, uint32_t, const sp&, const sp&, + status_t(HalDisplayId, uint32_t, const sp&, const sp&, ui::Dataspace)); - MOCK_METHOD1(presentAndGetReleaseFences, status_t(DisplayId)); - MOCK_METHOD2(setPowerMode, status_t(DisplayId, hal::PowerMode)); - MOCK_METHOD2(setActiveConfig, status_t(DisplayId, size_t)); - MOCK_METHOD2(setColorTransform, status_t(DisplayId, const mat4&)); - MOCK_METHOD1(disconnectDisplay, void(DisplayId)); + MOCK_METHOD1(presentAndGetReleaseFences, status_t(HalDisplayId)); + MOCK_METHOD2(setPowerMode, status_t(PhysicalDisplayId, hal::PowerMode)); + MOCK_METHOD2(setActiveConfig, status_t(HalDisplayId, size_t)); + MOCK_METHOD2(setColorTransform, status_t(HalDisplayId, const mat4&)); + MOCK_METHOD1(disconnectDisplay, void(HalDisplayId)); MOCK_CONST_METHOD1(hasDeviceComposition, bool(const std::optional&)); - MOCK_CONST_METHOD1(getPresentFence, sp(DisplayId)); - MOCK_CONST_METHOD2(getLayerReleaseFence, sp(DisplayId, HWC2::Layer*)); - MOCK_METHOD3(setOutputBuffer, status_t(DisplayId, const sp&, const sp&)); - MOCK_METHOD1(clearReleaseFences, void(DisplayId)); - MOCK_METHOD2(getHdrCapabilities, status_t(DisplayId, HdrCapabilities*)); - MOCK_CONST_METHOD1(getSupportedPerFrameMetadata, int32_t(DisplayId)); - MOCK_CONST_METHOD2(getRenderIntents, std::vector(DisplayId, ui::ColorMode)); - MOCK_METHOD2(getDataspaceSaturationMatrix, mat4(DisplayId, ui::Dataspace)); + MOCK_CONST_METHOD1(getPresentFence, sp(HalDisplayId)); + MOCK_CONST_METHOD2(getLayerReleaseFence, sp(HalDisplayId, HWC2::Layer*)); + MOCK_METHOD3(setOutputBuffer, + status_t(HalVirtualDisplayId, const sp&, const sp&)); + MOCK_METHOD1(clearReleaseFences, void(HalDisplayId)); + MOCK_METHOD2(getHdrCapabilities, status_t(HalDisplayId, HdrCapabilities*)); + MOCK_CONST_METHOD1(getSupportedPerFrameMetadata, int32_t(HalDisplayId)); + MOCK_CONST_METHOD2(getRenderIntents, + std::vector(HalDisplayId, ui::ColorMode)); + MOCK_METHOD2(getDataspaceSaturationMatrix, mat4(HalDisplayId, ui::Dataspace)); MOCK_METHOD4(getDisplayedContentSamplingAttributes, - status_t(DisplayId, ui::PixelFormat*, ui::Dataspace*, uint8_t*)); - MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(DisplayId, bool, uint8_t, uint64_t)); + status_t(HalDisplayId, ui::PixelFormat*, ui::Dataspace*, uint8_t*)); + MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t)); MOCK_METHOD4(getDisplayedContentSample, - status_t(DisplayId, uint64_t, uint64_t, DisplayedFrameStats*)); - MOCK_METHOD2(setDisplayBrightness, std::future(DisplayId, float)); - MOCK_METHOD2(getDisplayBrightnessSupport, status_t(DisplayId, bool*)); + status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*)); + MOCK_METHOD2(setDisplayBrightness, std::future(PhysicalDisplayId, float)); + MOCK_METHOD2(getDisplayBrightnessSupport, status_t(PhysicalDisplayId, bool*)); MOCK_METHOD2(onHotplug, std::optional(hal::HWDisplayId, hal::Connection)); MOCK_METHOD2(onVsync, bool(hal::HWDisplayId, int64_t)); - MOCK_METHOD2(setVsyncEnabled, void(DisplayId, hal::Vsync)); - MOCK_CONST_METHOD1(getRefreshTimestamp, nsecs_t(DisplayId)); - MOCK_CONST_METHOD1(isConnected, bool(DisplayId)); - MOCK_CONST_METHOD1(getConfigs, - std::vector>(DisplayId)); - MOCK_CONST_METHOD1(getActiveConfig, std::shared_ptr(DisplayId)); - MOCK_CONST_METHOD1(getActiveConfigIndex, int(DisplayId)); - MOCK_CONST_METHOD1(getColorModes, std::vector(DisplayId)); - MOCK_METHOD3(setActiveColorMode, status_t(DisplayId, ui::ColorMode, ui::RenderIntent)); + MOCK_METHOD2(setVsyncEnabled, void(PhysicalDisplayId, hal::Vsync)); + MOCK_CONST_METHOD1(getRefreshTimestamp, nsecs_t(PhysicalDisplayId)); + MOCK_CONST_METHOD1(isConnected, bool(PhysicalDisplayId)); + MOCK_CONST_METHOD1( + getConfigs, + std::vector>(PhysicalDisplayId)); + MOCK_CONST_METHOD1(getActiveConfig, + std::shared_ptr(PhysicalDisplayId)); + MOCK_CONST_METHOD1(getActiveConfigIndex, int(PhysicalDisplayId)); + MOCK_CONST_METHOD1(getColorModes, std::vector(PhysicalDisplayId)); + MOCK_METHOD3(setActiveColorMode, status_t(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent)); MOCK_CONST_METHOD0(isUsingVrComposer, bool()); - MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(DisplayId)); - MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(DisplayId)); - MOCK_CONST_METHOD1(getDisplayVsyncPeriod, nsecs_t(DisplayId)); + MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(PhysicalDisplayId)); + MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(PhysicalDisplayId)); + MOCK_CONST_METHOD1(getDisplayVsyncPeriod, nsecs_t(PhysicalDisplayId)); MOCK_METHOD4(setActiveConfigWithConstraints, - status_t(DisplayId, size_t, const hal::VsyncPeriodChangeConstraints&, + status_t(PhysicalDisplayId, size_t, const hal::VsyncPeriodChangeConstraints&, hal::VsyncPeriodChangeTimeline*)); - MOCK_METHOD2(setAutoLowLatencyMode, status_t(DisplayId, bool)); - MOCK_METHOD2(getSupportedContentTypes, status_t(DisplayId, std::vector*)); - MOCK_METHOD2(setContentType, status_t(DisplayId, hal::ContentType)); + MOCK_METHOD2(setAutoLowLatencyMode, status_t(PhysicalDisplayId, bool)); + MOCK_METHOD2(getSupportedContentTypes, + status_t(PhysicalDisplayId, std::vector*)); + MOCK_METHOD2(setContentType, status_t(PhysicalDisplayId, hal::ContentType)); MOCK_CONST_METHOD0(getSupportedLayerGenericMetadata, const std::unordered_map&()); diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 8d1eb36e15..6ce8a6b2ea 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -33,7 +33,7 @@ namespace { constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920; constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080; -constexpr std::optional DEFAULT_DISPLAY_ID = {PhysicalDisplayId(123u)}; +constexpr DisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId(123u); const std::string DEFAULT_DISPLAY_NAME = "Mock Display"; using testing::_; @@ -48,7 +48,7 @@ using testing::StrictMock; class RenderSurfaceTest : public testing::Test { public: RenderSurfaceTest() { - EXPECT_CALL(mDisplay, getId()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_ID)); + EXPECT_CALL(mDisplay, getId()).WillRepeatedly(Return(DEFAULT_DISPLAY_ID)); EXPECT_CALL(mDisplay, getName()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_NAME)); EXPECT_CALL(mCompositionEngine, getRenderEngine).WillRepeatedly(ReturnRef(mRenderEngine)); EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL)) diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index a1ccaad1bb..8aca71364a 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -201,17 +201,12 @@ ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() { } std::string DisplayDevice::getDebugName() const { - std::string displayId; - if (const auto id = getId()) { - displayId = to_string(*id) + ", "; - } - const char* type = "virtual"; if (mConnectionType) { type = *mConnectionType == DisplayConnectionType::Internal ? "internal" : "external"; } - return base::StringPrintf("DisplayDevice{%s%s%s, \"%s\"}", displayId.c_str(), type, + return base::StringPrintf("DisplayDevice{%s, %s%s, \"%s\"}", to_string(getId()).c_str(), type, isPrimary() ? ", primary" : "", mDisplayName.c_str()); } @@ -235,9 +230,7 @@ bool DisplayDevice::hasRenderIntent(ui::RenderIntent intent) const { return mCompositionDisplay->getDisplayColorProfile()->hasRenderIntent(intent); } -// ---------------------------------------------------------------------------- - -const std::optional& DisplayDevice::getId() const { +DisplayId DisplayDevice::getId() const { return mCompositionDisplay->getId(); } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 35a8b62053..fa684c0ab0 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -104,7 +105,15 @@ public: bool needsFiltering() const; ui::LayerStack getLayerStack() const; - const std::optional& getId() const; + // Returns the physical ID of this display. This function asserts the ID is physical and it + // shouldn't be called for other display types, e.g. virtual. + PhysicalDisplayId getPhysicalId() const { + const auto displayIdOpt = PhysicalDisplayId::tryCast(getId()); + LOG_FATAL_IF(!displayIdOpt); + return *displayIdOpt; + } + + DisplayId getId() const; const wp& getDisplayToken() const { return mDisplayToken; } int32_t getSequenceId() const { return mSequenceId; } diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 4c3b3e502d..14b54cd6ae 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -56,7 +56,7 @@ using ui::Dataspace; * */ -FramebufferSurface::FramebufferSurface(HWComposer& hwc, DisplayId displayId, +FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId, const sp& consumer, uint32_t maxWidth, uint32_t maxHeight) : ConsumerBase(consumer), diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index a1859f33bb..759943afa3 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "DisplayIdentification.h" @@ -39,7 +40,7 @@ class HWComposer; class FramebufferSurface : public ConsumerBase, public compositionengine::DisplaySurface { public: - FramebufferSurface(HWComposer& hwc, DisplayId displayId, + FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId, const sp& consumer, uint32_t maxWidth, uint32_t maxHeight); @@ -69,7 +70,7 @@ private: status_t nextBuffer(uint32_t& outSlot, sp& outBuffer, sp& outFence, ui::Dataspace& outDataspace); - const DisplayId mDisplayId; + const PhysicalDisplayId mDisplayId; // Framebuffer size has a dimension limitation in pixels based on the graphics capabilities of // the device. diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 1f03787ff4..89df84b580 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -240,15 +240,14 @@ namespace impl { class Display : public HWC2::Display { public: - Display(android::Hwc2::Composer& composer, - const std::unordered_set& capabilities, hal::HWDisplayId id, - hal::DisplayType type); + Display(android::Hwc2::Composer&, const std::unordered_set&, hal::HWDisplayId, + hal::DisplayType); ~Display() override; // Required by HWC2 hal::Error acceptChanges() override; hal::Error createLayer(Layer** outLayer) override; - hal::Error destroyLayer(Layer* layer) override; + hal::Error destroyLayer(Layer*) override; hal::Error getActiveConfig(std::shared_ptr* outConfig) const override; hal::Error getActiveConfigIndex(int* outIndex) const override; hal::Error getChangedCompositionTypes( @@ -258,8 +257,7 @@ public: int32_t getSupportedPerFrameMetadata() const override; hal::Error getRenderIntents(hal::ColorMode colorMode, std::vector* outRenderIntents) const override; - hal::Error getDataspaceSaturationMatrix(hal::Dataspace dataspace, - android::mat4* outMatrix) override; + hal::Error getDataspaceSaturationMatrix(hal::Dataspace, android::mat4* outMatrix) override; // Doesn't call into the HWC2 device, so no errors are possible std::vector> getConfigs() const override; @@ -285,11 +283,11 @@ public: hal::Error setClientTarget(uint32_t slot, const android::sp& target, const android::sp& acquireFence, hal::Dataspace dataspace) override; - hal::Error setColorMode(hal::ColorMode mode, hal::RenderIntent renderIntent) override; + hal::Error setColorMode(hal::ColorMode, hal::RenderIntent) override; hal::Error setColorTransform(const android::mat4& matrix, hal::ColorTransform hint) override; - hal::Error setOutputBuffer(const android::sp& buffer, + hal::Error setOutputBuffer(const android::sp&, const android::sp& releaseFence) override; - hal::Error setPowerMode(hal::PowerMode mode) override; + hal::Error setPowerMode(hal::PowerMode) override; hal::Error setVsyncEnabled(hal::Vsync enabled) override; hal::Error validate(uint32_t* outNumTypes, uint32_t* outNumRequests) override; hal::Error presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests, @@ -317,13 +315,13 @@ public: virtual bool isVsyncPeriodSwitchSupported() const override; private: - int32_t getAttribute(hal::HWConfigId configId, hal::Attribute attribute); - void loadConfig(hal::HWConfigId configId); + int32_t getAttribute(hal::HWConfigId, hal::Attribute); + void loadConfig(hal::HWConfigId); void loadConfigs(); // This may fail (and return a null pointer) if no layer with this ID exists // on this display - Layer* getLayerById(hal::HWLayerId id) const; + Layer* getLayerById(hal::HWLayerId) const; friend android::TestableSurfaceFlinger; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 195182af85..2fdbd3afde 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -186,7 +186,7 @@ bool HWComposer::hasCapability(hal::Capability capability) const { return mCapabilities.count(capability) > 0; } -bool HWComposer::hasDisplayCapability(DisplayId displayId, +bool HWComposer::hasDisplayCapability(HalDisplayId displayId, hal::DisplayCapability capability) const { RETURN_IF_INVALID_DISPLAY(displayId, false); return mDisplayData.at(displayId).hwcDisplay->getCapabilities().count(capability) > 0; @@ -214,10 +214,8 @@ bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) { RETURN_IF_INVALID_DISPLAY(*displayId, false); auto& displayData = mDisplayData[*displayId]; - if (displayData.isVirtual) { - LOG_DISPLAY_ERROR(*displayId, "Invalid operation on virtual display"); - return false; - } + LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s", + __FUNCTION__, to_string(*displayId).c_str()); { std::lock_guard lock(displayData.lastHwVsyncLock); @@ -244,11 +242,6 @@ bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) { std::optional HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height, ui::PixelFormat* format) { - if (mRemainingHwcVirtualDisplays == 0) { - ALOGE("%s: No remaining virtual displays", __FUNCTION__); - return {}; - } - if (SurfaceFlinger::maxVirtualDisplaySize != 0 && (width > SurfaceFlinger::maxVirtualDisplaySize || height > SurfaceFlinger::maxVirtualDisplaySize)) { @@ -256,31 +249,28 @@ std::optional HWComposer::allocateVirtualDisplay(uint32_t width, uint height, SurfaceFlinger::maxVirtualDisplaySize); return {}; } + + const auto displayId = mVirtualIdGenerator.nextId(); + if (!displayId) { + ALOGE("%s: No remaining virtual displays", __FUNCTION__); + return {}; + } + hal::HWDisplayId hwcDisplayId = 0; const auto error = static_cast( mComposer->createVirtualDisplay(width, height, format, &hwcDisplayId)); if (error != hal::Error::NONE) { ALOGE("%s: Failed to create HWC virtual display", __FUNCTION__); + mVirtualIdGenerator.markUnused(*displayId); return {}; } auto display = std::make_unique(*mComposer.get(), mCapabilities, hwcDisplayId, hal::DisplayType::VIRTUAL); display->setConnected(true); - - DisplayId displayId; - if (mFreeVirtualDisplayIds.empty()) { - displayId = getVirtualDisplayId(mNextVirtualDisplayId++); - } else { - displayId = *mFreeVirtualDisplayIds.begin(); - mFreeVirtualDisplayIds.erase(displayId); - } - - auto& displayData = mDisplayData[displayId]; + auto& displayData = mDisplayData[*displayId]; displayData.hwcDisplay = std::move(display); displayData.isVirtual = true; - - --mRemainingHwcVirtualDisplays; return displayId; } @@ -301,7 +291,7 @@ void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId, mPhysicalDisplayIdMap[hwcDisplayId] = displayId; } -HWC2::Layer* HWComposer::createLayer(DisplayId displayId) { +HWC2::Layer* HWComposer::createLayer(HalDisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId, nullptr); HWC2::Layer* layer; @@ -310,14 +300,14 @@ HWC2::Layer* HWComposer::createLayer(DisplayId displayId) { return layer; } -void HWComposer::destroyLayer(DisplayId displayId, HWC2::Layer* layer) { +void HWComposer::destroyLayer(HalDisplayId displayId, HWC2::Layer* layer) { RETURN_IF_INVALID_DISPLAY(displayId); auto error = mDisplayData[displayId].hwcDisplay->destroyLayer(layer); RETURN_IF_HWC_ERROR(error, displayId); } -nsecs_t HWComposer::getRefreshTimestamp(DisplayId displayId) const { +nsecs_t HWComposer::getRefreshTimestamp(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, 0); const auto& displayData = mDisplayData.at(displayId); // this returns the last refresh timestamp. @@ -329,13 +319,13 @@ nsecs_t HWComposer::getRefreshTimestamp(DisplayId displayId) const { return now - ((now - displayData.lastHwVsync) % vsyncPeriodNanos); } -bool HWComposer::isConnected(DisplayId displayId) const { +bool HWComposer::isConnected(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, false); return mDisplayData.at(displayId).hwcDisplay->isConnected(); } std::vector> HWComposer::getConfigs( - DisplayId displayId) const { + PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, {}); const auto& displayData = mDisplayData.at(displayId); @@ -349,7 +339,7 @@ std::vector> HWComposer::getConfigs } std::shared_ptr HWComposer::getActiveConfig( - DisplayId displayId) const { + PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, nullptr); std::shared_ptr config; @@ -371,7 +361,7 @@ std::shared_ptr HWComposer::getActiveConfig( // Composer 2.4 -DisplayConnectionType HWComposer::getDisplayConnectionType(DisplayId displayId) const { +DisplayConnectionType HWComposer::getDisplayConnectionType(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, DisplayConnectionType::Internal); const auto& hwcDisplay = mDisplayData.at(displayId).hwcDisplay; @@ -386,12 +376,12 @@ DisplayConnectionType HWComposer::getDisplayConnectionType(DisplayId displayId) return type; } -bool HWComposer::isVsyncPeriodSwitchSupported(DisplayId displayId) const { +bool HWComposer::isVsyncPeriodSwitchSupported(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, false); return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported(); } -nsecs_t HWComposer::getDisplayVsyncPeriod(DisplayId displayId) const { +nsecs_t HWComposer::getDisplayVsyncPeriod(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, 0); nsecs_t vsyncPeriodNanos; @@ -400,7 +390,7 @@ nsecs_t HWComposer::getDisplayVsyncPeriod(DisplayId displayId) const { return vsyncPeriodNanos; } -int HWComposer::getActiveConfigIndex(DisplayId displayId) const { +int HWComposer::getActiveConfigIndex(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, -1); int index; @@ -420,7 +410,7 @@ int HWComposer::getActiveConfigIndex(DisplayId displayId) const { return index; } -std::vector HWComposer::getColorModes(DisplayId displayId) const { +std::vector HWComposer::getColorModes(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, {}); std::vector modes; @@ -429,7 +419,7 @@ std::vector HWComposer::getColorModes(DisplayId displayId) const return modes; } -status_t HWComposer::setActiveColorMode(DisplayId displayId, ui::ColorMode mode, +status_t HWComposer::setActiveColorMode(PhysicalDisplayId displayId, ui::ColorMode mode, ui::RenderIntent renderIntent) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); @@ -443,14 +433,12 @@ status_t HWComposer::setActiveColorMode(DisplayId displayId, ui::ColorMode mode, return NO_ERROR; } -void HWComposer::setVsyncEnabled(DisplayId displayId, hal::Vsync enabled) { +void HWComposer::setVsyncEnabled(PhysicalDisplayId displayId, hal::Vsync enabled) { RETURN_IF_INVALID_DISPLAY(displayId); auto& displayData = mDisplayData[displayId]; - if (displayData.isVirtual) { - LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display"); - return; - } + LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s", + __FUNCTION__, to_string(displayId).c_str()); // NOTE: we use our own internal lock here because we have to call // into the HWC with the lock held, and we want to make sure @@ -471,7 +459,7 @@ void HWComposer::setVsyncEnabled(DisplayId displayId, hal::Vsync enabled) { ATRACE_INT(tag.c_str(), enabled == hal::Vsync::ENABLE ? 1 : 0); } -status_t HWComposer::setClientTarget(DisplayId displayId, uint32_t slot, +status_t HWComposer::setClientTarget(HalDisplayId displayId, uint32_t slot, const sp& acquireFence, const sp& target, ui::Dataspace dataspace) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); @@ -484,7 +472,7 @@ status_t HWComposer::setClientTarget(DisplayId displayId, uint32_t slot, } status_t HWComposer::getDeviceCompositionChanges( - DisplayId displayId, bool frameUsesClientComposition, + HalDisplayId displayId, bool frameUsesClientComposition, std::optional* outChanges) { ATRACE_CALL(); @@ -554,12 +542,12 @@ status_t HWComposer::getDeviceCompositionChanges( return NO_ERROR; } -sp HWComposer::getPresentFence(DisplayId displayId) const { +sp HWComposer::getPresentFence(HalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE); return mDisplayData.at(displayId).lastPresentFence; } -sp HWComposer::getLayerReleaseFence(DisplayId displayId, HWC2::Layer* layer) const { +sp HWComposer::getLayerReleaseFence(HalDisplayId displayId, HWC2::Layer* layer) const { RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE); const auto& displayFences = mDisplayData.at(displayId).releaseFences; auto fence = displayFences.find(layer); @@ -570,7 +558,7 @@ sp HWComposer::getLayerReleaseFence(DisplayId displayId, HWC2::Layer* lay return fence->second; } -status_t HWComposer::presentAndGetReleaseFences(DisplayId displayId) { +status_t HWComposer::presentAndGetReleaseFences(HalDisplayId displayId) { ATRACE_CALL(); RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); @@ -598,14 +586,12 @@ status_t HWComposer::presentAndGetReleaseFences(DisplayId displayId) { return NO_ERROR; } -status_t HWComposer::setPowerMode(DisplayId displayId, hal::PowerMode mode) { +status_t HWComposer::setPowerMode(PhysicalDisplayId displayId, hal::PowerMode mode) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto& displayData = mDisplayData[displayId]; - if (displayData.isVirtual) { - LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display"); - return INVALID_OPERATION; - } + LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s", + __FUNCTION__, to_string(displayId).c_str()); if (mode == hal::PowerMode::OFF) { setVsyncEnabled(displayId, hal::Vsync::DISABLE); @@ -654,7 +640,8 @@ status_t HWComposer::setPowerMode(DisplayId displayId, hal::PowerMode mode) { } status_t HWComposer::setActiveConfigWithConstraints( - DisplayId displayId, size_t configId, const hal::VsyncPeriodChangeConstraints& constraints, + PhysicalDisplayId displayId, size_t configId, + const hal::VsyncPeriodChangeConstraints& constraints, hal::VsyncPeriodChangeTimeline* outTimeline) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); @@ -671,7 +658,7 @@ status_t HWComposer::setActiveConfigWithConstraints( return NO_ERROR; } -status_t HWComposer::setColorTransform(DisplayId displayId, const mat4& transform) { +status_t HWComposer::setColorTransform(HalDisplayId displayId, const mat4& transform) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); auto& displayData = mDisplayData[displayId]; @@ -684,15 +671,14 @@ status_t HWComposer::setColorTransform(DisplayId displayId, const mat4& transfor return NO_ERROR; } -void HWComposer::disconnectDisplay(DisplayId displayId) { +void HWComposer::disconnectDisplay(HalDisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId); auto& displayData = mDisplayData[displayId]; // If this was a virtual display, add its slot back for reuse by future // virtual displays if (displayData.isVirtual) { - mFreeVirtualDisplayIds.insert(displayId); - ++mRemainingHwcVirtualDisplays; + mVirtualIdGenerator.markUnused(*HalVirtualDisplayId::tryCast(displayId)); } const auto hwcDisplayId = displayData.hwcDisplay->getId(); @@ -707,27 +693,25 @@ void HWComposer::disconnectDisplay(DisplayId displayId) { mDisplayData.erase(displayId); } -status_t HWComposer::setOutputBuffer(DisplayId displayId, const sp& acquireFence, +status_t HWComposer::setOutputBuffer(HalVirtualDisplayId displayId, const sp& acquireFence, const sp& buffer) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto& displayData = mDisplayData[displayId]; - if (!displayData.isVirtual) { - LOG_DISPLAY_ERROR(displayId, "Invalid operation on physical display"); - return INVALID_OPERATION; - } + LOG_FATAL_IF(!displayData.isVirtual, "%s: Invalid operation on physical display with ID %s", + __FUNCTION__, to_string(displayId).c_str()); auto error = displayData.hwcDisplay->setOutputBuffer(buffer, acquireFence); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } -void HWComposer::clearReleaseFences(DisplayId displayId) { +void HWComposer::clearReleaseFences(HalDisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId); mDisplayData[displayId].releaseFences.clear(); } -status_t HWComposer::getHdrCapabilities(DisplayId displayId, HdrCapabilities* outCapabilities) { +status_t HWComposer::getHdrCapabilities(HalDisplayId displayId, HdrCapabilities* outCapabilities) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); auto& hwcDisplay = mDisplayData[displayId].hwcDisplay; @@ -736,12 +720,12 @@ status_t HWComposer::getHdrCapabilities(DisplayId displayId, HdrCapabilities* ou return NO_ERROR; } -int32_t HWComposer::getSupportedPerFrameMetadata(DisplayId displayId) const { +int32_t HWComposer::getSupportedPerFrameMetadata(HalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, 0); return mDisplayData.at(displayId).hwcDisplay->getSupportedPerFrameMetadata(); } -std::vector HWComposer::getRenderIntents(DisplayId displayId, +std::vector HWComposer::getRenderIntents(HalDisplayId displayId, ui::ColorMode colorMode) const { RETURN_IF_INVALID_DISPLAY(displayId, {}); @@ -751,7 +735,7 @@ std::vector HWComposer::getRenderIntents(DisplayId displayId, return renderIntents; } -mat4 HWComposer::getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace dataspace) { +mat4 HWComposer::getDataspaceSaturationMatrix(HalDisplayId displayId, ui::Dataspace dataspace) { RETURN_IF_INVALID_DISPLAY(displayId, {}); mat4 matrix; @@ -761,7 +745,7 @@ mat4 HWComposer::getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace return matrix; } -status_t HWComposer::getDisplayedContentSamplingAttributes(DisplayId displayId, +status_t HWComposer::getDisplayedContentSamplingAttributes(HalDisplayId displayId, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, uint8_t* outComponentMask) { @@ -775,7 +759,7 @@ status_t HWComposer::getDisplayedContentSamplingAttributes(DisplayId displayId, return NO_ERROR; } -status_t HWComposer::setDisplayContentSamplingEnabled(DisplayId displayId, bool enabled, +status_t HWComposer::setDisplayContentSamplingEnabled(HalDisplayId displayId, bool enabled, uint8_t componentMask, uint64_t maxFrames) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = @@ -789,7 +773,7 @@ status_t HWComposer::setDisplayContentSamplingEnabled(DisplayId displayId, bool return NO_ERROR; } -status_t HWComposer::getDisplayedContentSample(DisplayId displayId, uint64_t maxFrames, +status_t HWComposer::getDisplayedContentSample(HalDisplayId displayId, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = @@ -799,7 +783,8 @@ status_t HWComposer::getDisplayedContentSample(DisplayId displayId, uint64_t max return NO_ERROR; } -std::future HWComposer::setDisplayBrightness(DisplayId displayId, float brightness) { +std::future HWComposer::setDisplayBrightness(PhysicalDisplayId displayId, + float brightness) { RETURN_IF_INVALID_DISPLAY(displayId, promise::yield(BAD_INDEX)); auto& display = mDisplayData[displayId].hwcDisplay; @@ -816,7 +801,7 @@ std::future HWComposer::setDisplayBrightness(DisplayId displayId, floa }); } -status_t HWComposer::setAutoLowLatencyMode(DisplayId displayId, bool on) { +status_t HWComposer::setAutoLowLatencyMode(PhysicalDisplayId displayId, bool on) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId].hwcDisplay->setAutoLowLatencyMode(on); if (error == hal::Error::UNSUPPORTED) { @@ -830,7 +815,7 @@ status_t HWComposer::setAutoLowLatencyMode(DisplayId displayId, bool on) { } status_t HWComposer::getSupportedContentTypes( - DisplayId displayId, std::vector* outSupportedContentTypes) { + PhysicalDisplayId displayId, std::vector* outSupportedContentTypes) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId].hwcDisplay->getSupportedContentTypes(outSupportedContentTypes); @@ -840,7 +825,7 @@ status_t HWComposer::getSupportedContentTypes( return NO_ERROR; } -status_t HWComposer::setContentType(DisplayId displayId, hal::ContentType contentType) { +status_t HWComposer::setContentType(PhysicalDisplayId displayId, hal::ContentType contentType) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId].hwcDisplay->setContentType(contentType); if (error == hal::Error::UNSUPPORTED) { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 488cdc5105..028a9a4566 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -38,6 +38,7 @@ #include #include +#include "DisplayIdGenerator.h" #include "DisplayIdentification.h" #include "HWC2.h" #include "Hal.h" @@ -88,7 +89,7 @@ public: DisplayIdentificationData* outData) const = 0; virtual bool hasCapability(hal::Capability) const = 0; - virtual bool hasDisplayCapability(DisplayId, hal::DisplayCapability) const = 0; + virtual bool hasDisplayCapability(HalDisplayId, hal::DisplayCapability) const = 0; // Attempts to allocate a virtual display and returns its ID if created on the HWC device. virtual std::optional allocateVirtualDisplay(uint32_t width, uint32_t height, @@ -97,9 +98,9 @@ public: virtual void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) = 0; // Attempts to create a new layer on this display - virtual HWC2::Layer* createLayer(DisplayId) = 0; + virtual HWC2::Layer* createLayer(HalDisplayId) = 0; // Destroy a previously created layer - virtual void destroyLayer(DisplayId, HWC2::Layer*) = 0; + virtual void destroyLayer(HalDisplayId, HWC2::Layer*) = 0; // Gets any required composition change requests from the HWC device. // @@ -109,61 +110,60 @@ public: // with fewer handshakes, but this does not work if client composition is // expected. virtual status_t getDeviceCompositionChanges( - DisplayId, bool frameUsesClientComposition, + HalDisplayId, bool frameUsesClientComposition, std::optional* outChanges) = 0; - virtual status_t setClientTarget(DisplayId, uint32_t slot, const sp& acquireFence, + virtual status_t setClientTarget(HalDisplayId, uint32_t slot, const sp& acquireFence, const sp& target, ui::Dataspace) = 0; // Present layers to the display and read releaseFences. - virtual status_t presentAndGetReleaseFences(DisplayId) = 0; + virtual status_t presentAndGetReleaseFences(HalDisplayId) = 0; // set power mode - virtual status_t setPowerMode(DisplayId, hal::PowerMode) = 0; + virtual status_t setPowerMode(PhysicalDisplayId, hal::PowerMode) = 0; // Sets a color transform to be applied to the result of composition - virtual status_t setColorTransform(DisplayId, const mat4& transform) = 0; + virtual status_t setColorTransform(HalDisplayId, const mat4& transform) = 0; - // reset state when an external, non-virtual display is disconnected - virtual void disconnectDisplay(DisplayId) = 0; + // reset state when a display is disconnected + virtual void disconnectDisplay(HalDisplayId) = 0; // get the present fence received from the last call to present. - virtual sp getPresentFence(DisplayId) const = 0; + virtual sp getPresentFence(HalDisplayId) const = 0; // Get last release fence for the given layer - virtual sp getLayerReleaseFence(DisplayId, HWC2::Layer*) const = 0; + virtual sp getLayerReleaseFence(HalDisplayId, HWC2::Layer*) const = 0; // Set the output buffer and acquire fence for a virtual display. - // Returns INVALID_OPERATION if displayId is not a virtual display. - virtual status_t setOutputBuffer(DisplayId, const sp& acquireFence, + virtual status_t setOutputBuffer(HalVirtualDisplayId, const sp& acquireFence, const sp& buffer) = 0; // After SurfaceFlinger has retrieved the release fences for all the frames, // it can call this to clear the shared pointers in the release fence map - virtual void clearReleaseFences(DisplayId) = 0; + virtual void clearReleaseFences(HalDisplayId) = 0; // Fetches the HDR capabilities of the given display - virtual status_t getHdrCapabilities(DisplayId, HdrCapabilities* outCapabilities) = 0; + virtual status_t getHdrCapabilities(HalDisplayId, HdrCapabilities* outCapabilities) = 0; - virtual int32_t getSupportedPerFrameMetadata(DisplayId) const = 0; + virtual int32_t getSupportedPerFrameMetadata(HalDisplayId) const = 0; // Returns the available RenderIntent of the given display. - virtual std::vector getRenderIntents(DisplayId, ui::ColorMode) const = 0; + virtual std::vector getRenderIntents(HalDisplayId, ui::ColorMode) const = 0; - virtual mat4 getDataspaceSaturationMatrix(DisplayId, ui::Dataspace) = 0; + virtual mat4 getDataspaceSaturationMatrix(HalDisplayId, ui::Dataspace) = 0; // Returns the attributes of the color sampling engine. - virtual status_t getDisplayedContentSamplingAttributes(DisplayId, ui::PixelFormat* outFormat, + virtual status_t getDisplayedContentSamplingAttributes(HalDisplayId, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, uint8_t* outComponentMask) = 0; - virtual status_t setDisplayContentSamplingEnabled(DisplayId, bool enabled, + virtual status_t setDisplayContentSamplingEnabled(HalDisplayId, bool enabled, uint8_t componentMask, uint64_t maxFrames) = 0; - virtual status_t getDisplayedContentSample(DisplayId, uint64_t maxFrames, uint64_t timestamp, + virtual status_t getDisplayedContentSample(HalDisplayId, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) = 0; // Sets the brightness of a display. - virtual std::future setDisplayBrightness(DisplayId, float brightness) = 0; + virtual std::future setDisplayBrightness(PhysicalDisplayId, float brightness) = 0; // Events handling --------------------------------------------------------- @@ -174,33 +174,35 @@ public: hal::Connection) = 0; virtual bool onVsync(hal::HWDisplayId, int64_t timestamp) = 0; - virtual void setVsyncEnabled(DisplayId, hal::Vsync enabled) = 0; + virtual void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) = 0; - virtual nsecs_t getRefreshTimestamp(DisplayId) const = 0; - virtual bool isConnected(DisplayId) const = 0; + virtual nsecs_t getRefreshTimestamp(PhysicalDisplayId) const = 0; + virtual bool isConnected(PhysicalDisplayId) const = 0; // Non-const because it can update configMap inside of mDisplayData virtual std::vector> getConfigs( - DisplayId) const = 0; + PhysicalDisplayId) const = 0; - virtual std::shared_ptr getActiveConfig(DisplayId) const = 0; - virtual int getActiveConfigIndex(DisplayId) const = 0; + virtual std::shared_ptr getActiveConfig( + PhysicalDisplayId) const = 0; + virtual int getActiveConfigIndex(PhysicalDisplayId) const = 0; - virtual std::vector getColorModes(DisplayId) const = 0; + virtual std::vector getColorModes(PhysicalDisplayId) const = 0; - virtual status_t setActiveColorMode(DisplayId, ui::ColorMode mode, ui::RenderIntent) = 0; + virtual status_t setActiveColorMode(PhysicalDisplayId, ui::ColorMode mode, + ui::RenderIntent) = 0; // Composer 2.4 - virtual DisplayConnectionType getDisplayConnectionType(DisplayId) const = 0; - virtual bool isVsyncPeriodSwitchSupported(DisplayId) const = 0; - virtual nsecs_t getDisplayVsyncPeriod(DisplayId) const = 0; + virtual DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const = 0; + virtual bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const = 0; + virtual nsecs_t getDisplayVsyncPeriod(PhysicalDisplayId) const = 0; virtual status_t setActiveConfigWithConstraints( - DisplayId, size_t configId, const hal::VsyncPeriodChangeConstraints&, + PhysicalDisplayId, size_t configId, const hal::VsyncPeriodChangeConstraints&, hal::VsyncPeriodChangeTimeline* outTimeline) = 0; - virtual status_t setAutoLowLatencyMode(DisplayId, bool on) = 0; + virtual status_t setAutoLowLatencyMode(PhysicalDisplayId, bool on) = 0; virtual status_t getSupportedContentTypes( - DisplayId, std::vector* outSupportedContentTypes) = 0; - virtual status_t setContentType(DisplayId, hal::ContentType) = 0; + PhysicalDisplayId, std::vector* outSupportedContentTypes) = 0; + virtual status_t setContentType(PhysicalDisplayId, hal::ContentType) = 0; virtual const std::unordered_map& getSupportedLayerGenericMetadata() const = 0; @@ -232,7 +234,7 @@ public: DisplayIdentificationData* outData) const override; bool hasCapability(hal::Capability) const override; - bool hasDisplayCapability(DisplayId, hal::DisplayCapability) const override; + bool hasDisplayCapability(HalDisplayId, hal::DisplayCapability) const override; // Attempts to allocate a virtual display and returns its ID if created on the HWC device. std::optional allocateVirtualDisplay(uint32_t width, uint32_t height, @@ -242,63 +244,62 @@ public: void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) override; // Attempts to create a new layer on this display - HWC2::Layer* createLayer(DisplayId) override; + HWC2::Layer* createLayer(HalDisplayId) override; // Destroy a previously created layer - void destroyLayer(DisplayId, HWC2::Layer*) override; + void destroyLayer(HalDisplayId, HWC2::Layer*) override; status_t getDeviceCompositionChanges( - DisplayId, bool frameUsesClientComposition, + HalDisplayId, bool frameUsesClientComposition, std::optional* outChanges) override; - status_t setClientTarget(DisplayId, uint32_t slot, const sp& acquireFence, + status_t setClientTarget(HalDisplayId, uint32_t slot, const sp& acquireFence, const sp& target, ui::Dataspace) override; // Present layers to the display and read releaseFences. - status_t presentAndGetReleaseFences(DisplayId) override; + status_t presentAndGetReleaseFences(HalDisplayId) override; // set power mode - status_t setPowerMode(DisplayId, hal::PowerMode mode) override; + status_t setPowerMode(PhysicalDisplayId, hal::PowerMode mode) override; // Sets a color transform to be applied to the result of composition - status_t setColorTransform(DisplayId, const mat4& transform) override; + status_t setColorTransform(HalDisplayId, const mat4& transform) override; - // reset state when an external, non-virtual display is disconnected - void disconnectDisplay(DisplayId) override; + // reset state when a display is disconnected + void disconnectDisplay(HalDisplayId) override; // get the present fence received from the last call to present. - sp getPresentFence(DisplayId) const override; + sp getPresentFence(HalDisplayId) const override; // Get last release fence for the given layer - sp getLayerReleaseFence(DisplayId, HWC2::Layer*) const override; + sp getLayerReleaseFence(HalDisplayId, HWC2::Layer*) const override; // Set the output buffer and acquire fence for a virtual display. - // Returns INVALID_OPERATION if displayId is not a virtual display. - status_t setOutputBuffer(DisplayId, const sp& acquireFence, + status_t setOutputBuffer(HalVirtualDisplayId, const sp& acquireFence, const sp& buffer) override; // After SurfaceFlinger has retrieved the release fences for all the frames, // it can call this to clear the shared pointers in the release fence map - void clearReleaseFences(DisplayId) override; + void clearReleaseFences(HalDisplayId) override; // Fetches the HDR capabilities of the given display - status_t getHdrCapabilities(DisplayId, HdrCapabilities* outCapabilities) override; + status_t getHdrCapabilities(HalDisplayId, HdrCapabilities* outCapabilities) override; - int32_t getSupportedPerFrameMetadata(DisplayId) const override; + int32_t getSupportedPerFrameMetadata(HalDisplayId) const override; // Returns the available RenderIntent of the given display. - std::vector getRenderIntents(DisplayId, ui::ColorMode) const override; + std::vector getRenderIntents(HalDisplayId, ui::ColorMode) const override; - mat4 getDataspaceSaturationMatrix(DisplayId, ui::Dataspace) override; + mat4 getDataspaceSaturationMatrix(HalDisplayId, ui::Dataspace) override; // Returns the attributes of the color sampling engine. - status_t getDisplayedContentSamplingAttributes(DisplayId, ui::PixelFormat* outFormat, + status_t getDisplayedContentSamplingAttributes(HalDisplayId, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, uint8_t* outComponentMask) override; - status_t setDisplayContentSamplingEnabled(DisplayId, bool enabled, uint8_t componentMask, + status_t setDisplayContentSamplingEnabled(HalDisplayId, bool enabled, uint8_t componentMask, uint64_t maxFrames) override; - status_t getDisplayedContentSample(DisplayId, uint64_t maxFrames, uint64_t timestamp, + status_t getDisplayedContentSample(HalDisplayId, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) override; - std::future setDisplayBrightness(DisplayId, float brightness) override; + std::future setDisplayBrightness(PhysicalDisplayId, float brightness) override; // Events handling --------------------------------------------------------- @@ -307,31 +308,32 @@ public: std::optional onHotplug(hal::HWDisplayId, hal::Connection) override; bool onVsync(hal::HWDisplayId, int64_t timestamp) override; - void setVsyncEnabled(DisplayId, hal::Vsync enabled) override; + void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) override; - nsecs_t getRefreshTimestamp(DisplayId) const override; - bool isConnected(DisplayId) const override; + nsecs_t getRefreshTimestamp(PhysicalDisplayId) const override; + bool isConnected(PhysicalDisplayId) const override; // Non-const because it can update configMap inside of mDisplayData - std::vector> getConfigs(DisplayId) const override; + std::vector> getConfigs( + PhysicalDisplayId) const override; - std::shared_ptr getActiveConfig(DisplayId) const override; - int getActiveConfigIndex(DisplayId) const override; + std::shared_ptr getActiveConfig(PhysicalDisplayId) const override; + int getActiveConfigIndex(PhysicalDisplayId) const override; - std::vector getColorModes(DisplayId) const override; + std::vector getColorModes(PhysicalDisplayId) const override; - status_t setActiveColorMode(DisplayId, ui::ColorMode, ui::RenderIntent) override; + status_t setActiveColorMode(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent) override; // Composer 2.4 - DisplayConnectionType getDisplayConnectionType(DisplayId) const override; - bool isVsyncPeriodSwitchSupported(DisplayId) const override; - nsecs_t getDisplayVsyncPeriod(DisplayId) const override; - status_t setActiveConfigWithConstraints(DisplayId, size_t configId, + DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override; + bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const override; + nsecs_t getDisplayVsyncPeriod(PhysicalDisplayId) const override; + status_t setActiveConfigWithConstraints(PhysicalDisplayId, size_t configId, const hal::VsyncPeriodChangeConstraints&, hal::VsyncPeriodChangeTimeline* outTimeline) override; - status_t setAutoLowLatencyMode(DisplayId, bool) override; - status_t getSupportedContentTypes(DisplayId, std::vector*) override; - status_t setContentType(DisplayId, hal::ContentType) override; + status_t setAutoLowLatencyMode(PhysicalDisplayId, bool) override; + status_t getSupportedContentTypes(PhysicalDisplayId, std::vector*) override; + status_t setContentType(PhysicalDisplayId, hal::ContentType) override; const std::unordered_map& getSupportedLayerGenericMetadata() const override; @@ -385,7 +387,7 @@ private: nsecs_t lastHwVsync GUARDED_BY(lastHwVsyncLock) = 0; }; - std::unordered_map mDisplayData; + std::unordered_map mDisplayData; std::unique_ptr mComposer; std::unordered_set mCapabilities; @@ -397,9 +399,7 @@ private: std::optional mExternalHwcDisplayId; bool mHasMultiDisplaySupport = false; - std::unordered_set mFreeVirtualDisplayIds; - uint32_t mNextVirtualDisplayId = 0; - uint32_t mRemainingHwcVirtualDisplays{getMaxVirtualDisplayCount()}; + RandomDisplayIdGenerator mVirtualIdGenerator{getMaxVirtualDisplayCount()}; }; } // namespace impl diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index fba3261388..247ee23fa7 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -57,8 +57,7 @@ static const char* dbgCompositionTypeStr(compositionengine::DisplaySurface::Comp } } -VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, - const std::optional& displayId, +VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, VirtualDisplayId displayId, const sp& sink, const sp& bqProducer, const sp& bqConsumer, @@ -125,7 +124,7 @@ VirtualDisplaySurface::~VirtualDisplaySurface() { } status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) { - if (!mDisplayId) { + if (GpuVirtualDisplayId::tryCast(mDisplayId)) { return NO_ERROR; } @@ -139,7 +138,7 @@ status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) { } status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { - if (!mDisplayId) { + if (GpuVirtualDisplayId::tryCast(mDisplayId)) { return NO_ERROR; } @@ -187,7 +186,7 @@ status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { } status_t VirtualDisplaySurface::advanceFrame() { - if (!mDisplayId) { + if (GpuVirtualDisplayId::tryCast(mDisplayId)) { return NO_ERROR; } @@ -219,9 +218,11 @@ status_t VirtualDisplaySurface::advanceFrame() { mFbProducerSlot, fbBuffer.get(), mOutputProducerSlot, outBuffer.get()); + const auto halDisplayId = HalVirtualDisplayId::tryCast(mDisplayId); + LOG_FATAL_IF(!halDisplayId); // At this point we know the output buffer acquire fence, // so update HWC state with it. - mHwc.setOutputBuffer(*mDisplayId, mOutputFence, outBuffer); + mHwc.setOutputBuffer(*halDisplayId, mOutputFence, outBuffer); status_t result = NO_ERROR; if (fbBuffer != nullptr) { @@ -230,7 +231,7 @@ status_t VirtualDisplaySurface::advanceFrame() { mHwcBufferCache.getHwcBuffer(mFbProducerSlot, fbBuffer, &hwcSlot, &hwcBuffer); // TODO: Correctly propagate the dataspace from GL composition - result = mHwc.setClientTarget(*mDisplayId, hwcSlot, mFbFence, hwcBuffer, + result = mHwc.setClientTarget(*halDisplayId, hwcSlot, mFbFence, hwcBuffer, ui::Dataspace::UNKNOWN); } @@ -238,7 +239,8 @@ status_t VirtualDisplaySurface::advanceFrame() { } void VirtualDisplaySurface::onFrameCommitted() { - if (!mDisplayId) { + const auto halDisplayId = HalVirtualDisplayId::tryCast(mDisplayId); + if (!halDisplayId) { return; } @@ -246,7 +248,7 @@ void VirtualDisplaySurface::onFrameCommitted() { "Unexpected onFrameCommitted() in %s state", dbgStateStr()); mDbgState = DBG_STATE_IDLE; - sp retireFence = mHwc.getPresentFence(*mDisplayId); + sp retireFence = mHwc.getPresentFence(*halDisplayId); if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) { // release the scratch buffer back to the pool Mutex::Autolock lock(mMutex); @@ -301,7 +303,7 @@ const sp& VirtualDisplaySurface::getClientTargetAcquireFence() const { status_t VirtualDisplaySurface::requestBuffer(int pslot, sp* outBuf) { - if (!mDisplayId) { + if (GpuVirtualDisplayId::tryCast(mDisplayId)) { return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf); } @@ -323,7 +325,7 @@ status_t VirtualDisplaySurface::setAsyncMode(bool async) { status_t VirtualDisplaySurface::dequeueBuffer(Source source, PixelFormat format, uint64_t usage, int* sslot, sp* fence) { - LOG_FATAL_IF(!mDisplayId); + LOG_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId)); status_t result = mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight, @@ -369,7 +371,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, uint PixelFormat format, uint64_t usage, uint64_t* outBufferAge, FrameEventHistoryDelta* outTimestamps) { - if (!mDisplayId) { + if (GpuVirtualDisplayId::tryCast(mDisplayId)) { return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage, outBufferAge, outTimestamps); } @@ -456,7 +458,7 @@ status_t VirtualDisplaySurface::attachBuffer(int* /* outSlot */, status_t VirtualDisplaySurface::queueBuffer(int pslot, const QueueBufferInput& input, QueueBufferOutput* output) { - if (!mDisplayId) { + if (GpuVirtualDisplayId::tryCast(mDisplayId)) { return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output); } @@ -514,7 +516,7 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, status_t VirtualDisplaySurface::cancelBuffer(int pslot, const sp& fence) { - if (!mDisplayId) { + if (GpuVirtualDisplayId::tryCast(mDisplayId)) { return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence); } @@ -626,7 +628,7 @@ void VirtualDisplaySurface::resetPerFrameState() { } status_t VirtualDisplaySurface::refreshOutputBuffer() { - LOG_FATAL_IF(!mDisplayId); + LOG_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId)); if (mOutputProducerSlot >= 0) { mSource[SOURCE_SINK]->cancelBuffer( @@ -645,7 +647,9 @@ status_t VirtualDisplaySurface::refreshOutputBuffer() { // until after GPU calls queueBuffer(). So here we just set the buffer // (for use in HWC prepare) but not the fence; we'll call this again with // the proper fence once we have it. - result = mHwc.setOutputBuffer(*mDisplayId, Fence::NO_FENCE, + const auto halDisplayId = HalVirtualDisplayId::tryCast(mDisplayId); + LOG_FATAL_IF(!halDisplayId); + result = mHwc.setOutputBuffer(*halDisplayId, Fence::NO_FENCE, mProducerBuffers[mOutputProducerSlot]); return result; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 3cbad8f8ae..19746252ab 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "DisplayIdentification.h" @@ -77,8 +78,7 @@ class VirtualDisplaySurface : public compositionengine::DisplaySurface, public BnGraphicBufferProducer, private ConsumerBase { public: - VirtualDisplaySurface(HWComposer& hwc, const std::optional& displayId, - const sp& sink, + VirtualDisplaySurface(HWComposer&, VirtualDisplayId, const sp& sink, const sp& bqProducer, const sp& bqConsumer, const std::string& name); @@ -86,7 +86,7 @@ public: // DisplaySurface interface // virtual status_t beginFrame(bool mustRecompose); - virtual status_t prepareFrame(CompositionType compositionType); + virtual status_t prepareFrame(CompositionType); virtual status_t advanceFrame(); virtual void onFrameCommitted(); virtual void dumpAsString(String8& result) const; @@ -104,25 +104,22 @@ private: virtual status_t requestBuffer(int pslot, sp* outBuf); virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); virtual status_t setAsyncMode(bool async); - virtual status_t dequeueBuffer(int* pslot, sp* fence, uint32_t w, uint32_t h, - PixelFormat format, uint64_t usage, uint64_t* outBufferAge, + virtual status_t dequeueBuffer(int* pslot, sp*, uint32_t w, uint32_t h, PixelFormat, + uint64_t usage, uint64_t* outBufferAge, FrameEventHistoryDelta* outTimestamps); virtual status_t detachBuffer(int slot); - virtual status_t detachNextBuffer(sp* outBuffer, - sp* outFence); - virtual status_t attachBuffer(int* slot, const sp& buffer); - virtual status_t queueBuffer(int pslot, - const QueueBufferInput& input, QueueBufferOutput* output); - virtual status_t cancelBuffer(int pslot, const sp& fence); + virtual status_t detachNextBuffer(sp* outBuffer, sp* outFence); + virtual status_t attachBuffer(int* slot, const sp&); + virtual status_t queueBuffer(int pslot, const QueueBufferInput&, QueueBufferOutput*); + virtual status_t cancelBuffer(int pslot, const sp&); virtual int query(int what, int* value); - virtual status_t connect(const sp& listener, - int api, bool producerControlledByApp, QueueBufferOutput* output); - virtual status_t disconnect(int api, DisconnectMode mode); + virtual status_t connect(const sp&, int api, bool producerControlledByApp, + QueueBufferOutput*); + virtual status_t disconnect(int api, DisconnectMode); virtual status_t setSidebandStream(const sp& stream); - virtual void allocateBuffers(uint32_t width, uint32_t height, - PixelFormat format, uint64_t usage); + virtual void allocateBuffers(uint32_t width, uint32_t height, PixelFormat, uint64_t usage); virtual status_t allowAllocation(bool allow); - virtual status_t setGenerationNumber(uint32_t generationNumber); + virtual status_t setGenerationNumber(uint32_t); virtual String8 getConsumerName() const override; virtual status_t setSharedBufferMode(bool sharedBufferMode) override; virtual status_t setAutoRefresh(bool autoRefresh) override; @@ -135,10 +132,9 @@ private: // // Utility methods // - static Source fbSourceForCompositionType(CompositionType type); - status_t dequeueBuffer(Source source, PixelFormat format, uint64_t usage, - int* sslot, sp* fence); - void updateQueueBufferOutput(QueueBufferOutput&& qbo); + static Source fbSourceForCompositionType(CompositionType); + status_t dequeueBuffer(Source, PixelFormat, uint64_t usage, int* sslot, sp*); + void updateQueueBufferOutput(QueueBufferOutput&&); void resetPerFrameState(); status_t refreshOutputBuffer(); @@ -148,14 +144,14 @@ private: // internally in the VirtualDisplaySurface. To minimize the number of times // a producer slot switches which source it comes from, we map source slot // numbers to producer slot numbers differently for each source. - static int mapSource2ProducerSlot(Source source, int sslot); - static int mapProducer2SourceSlot(Source source, int pslot); + static int mapSource2ProducerSlot(Source, int sslot); + static int mapProducer2SourceSlot(Source, int pslot); // // Immutable after construction // HWComposer& mHwc; - const std::optional mDisplayId; + const VirtualDisplayId mDisplayId; const std::string mDisplayName; sp mSource[2]; // indexed by SOURCE_* uint32_t mDefaultOutputFormat; diff --git a/services/surfaceflinger/DisplayIdGenerator.h b/services/surfaceflinger/DisplayIdGenerator.h new file mode 100644 index 0000000000..e7c69a8094 --- /dev/null +++ b/services/surfaceflinger/DisplayIdGenerator.h @@ -0,0 +1,75 @@ +/* + * 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 { + +template +class DisplayIdGenerator { +public: + virtual std::optional nextId() = 0; + virtual void markUnused(T id) = 0; + +protected: + ~DisplayIdGenerator() {} +}; + +template +class RandomDisplayIdGenerator final : public DisplayIdGenerator { +public: + explicit RandomDisplayIdGenerator(size_t maxIdsCount = std::numeric_limits::max()) + : mMaxIdsCount(maxIdsCount) {} + + std::optional nextId() override { + if (mUsedIds.size() >= mMaxIdsCount) { + return std::nullopt; + } + + constexpr int kMaxAttempts = 1000; + + for (int attempts = 0; attempts < kMaxAttempts; attempts++) { + const auto baseId = mDistribution(mGenerator); + const T id(baseId); + if (mUsedIds.count(id) == 0) { + mUsedIds.insert(id); + return id; + } + } + + LOG_ALWAYS_FATAL("Couldn't generate ID after %d attempts", kMaxAttempts); + } + + void markUnused(T id) override { mUsedIds.erase(id); } + +private: + const size_t mMaxIdsCount; + + std::unordered_set mUsedIds; + std::default_random_engine mGenerator{std::random_device()()}; + std::uniform_int_distribution mDistribution; +}; + +} // namespace android \ No newline at end of file diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9bfc63aaa2..b4868a9c49 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -717,7 +717,8 @@ void SurfaceFlinger::init() { processDisplayHotplugEventsLocked(); const auto display = getDefaultDisplayDeviceLocked(); LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback."); - LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(*display->getId()), + const auto displayId = display->getPhysicalId(); + LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(displayId), "Internal display is disconnected."); // initialize our drawing state @@ -1078,8 +1079,8 @@ void SurfaceFlinger::setActiveConfigInternal() { const nsecs_t vsyncPeriod = mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId) .getVsyncPeriod(); - mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, - static_cast(*display->getId()), + const auto physicalId = display->getPhysicalId(); + mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, physicalId, mUpcomingActiveConfig.configId, vsyncPeriod); } } @@ -1128,8 +1129,7 @@ void SurfaceFlinger::performSetActiveConfig() { } mUpcomingActiveConfig = *desiredActiveConfig; - const auto displayId = display->getId(); - LOG_ALWAYS_FATAL_IF(!displayId); + const auto displayId = display->getPhysicalId(); ATRACE_INT("ActiveConfigFPS_HWC", refreshRate.getFps()); @@ -1140,7 +1140,7 @@ void SurfaceFlinger::performSetActiveConfig() { hal::VsyncPeriodChangeTimeline outTimeline; auto status = - getHwComposer().setActiveConfigWithConstraints(*displayId, + getHwComposer().setActiveConfigWithConstraints(displayId, mUpcomingActiveConfig.configId.value(), constraints, &outTimeline); if (status != NO_ERROR) { @@ -1665,7 +1665,7 @@ void SurfaceFlinger::setVsyncEnabled(bool enabled) { if (const auto display = getDefaultDisplayDeviceLocked(); display && display->isPoweredOn()) { - getHwComposer().setVsyncEnabled(*display->getId(), mHWCVsyncPendingState); + getHwComposer().setVsyncEnabled(display->getPhysicalId(), mHWCVsyncPendingState); } })); } @@ -2120,7 +2120,7 @@ void SurfaceFlinger::postComposition() getBE().mDisplayTimeline.updateSignalTimes(); mPreviousPresentFences[1] = mPreviousPresentFences[0]; mPreviousPresentFences[0] = - display ? getHwComposer().getPresentFence(*display->getId()) : Fence::NO_FENCE; + display ? getHwComposer().getPresentFence(display->getPhysicalId()) : Fence::NO_FENCE; auto presentFenceTime = std::make_shared(mPreviousPresentFences[0]); getBE().mDisplayTimeline.push(presentFenceTime); @@ -2154,7 +2154,8 @@ void SurfaceFlinger::postComposition() mScheduler->addPresentFence(presentFenceTime); } - const bool isDisplayConnected = display && getHwComposer().isConnected(*display->getId()); + const bool isDisplayConnected = + display && getHwComposer().isConnected(display->getPhysicalId()); if (!hasSyncFramework) { if (isDisplayConnected && display->isPoweredOn()) { @@ -2171,7 +2172,8 @@ void SurfaceFlinger::postComposition() } else if (isDisplayConnected) { // The HWC doesn't support present fences, so use the refresh // timestamp instead. - const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(*display->getId()); + const nsecs_t presentTime = + getHwComposer().getRefreshTimestamp(display->getPhysicalId()); mAnimFrameTracker.setActualPresentTime(presentTime); } mAnimFrameTracker.advanceFrame(); @@ -2273,7 +2275,7 @@ void SurfaceFlinger::computeLayerBounds() { void SurfaceFlinger::postFrame() { const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); - if (display && getHwComposer().isConnected(*display->getId())) { + if (display && getHwComposer().isConnected(display->getPhysicalId())) { uint32_t flipCount = display->getPageFlipCount(); if (flipCount % LOG_FRAME_STATS_PERIOD == 0) { logFrameStats(); @@ -2378,7 +2380,6 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( const DisplayDeviceState& state, const sp& displaySurface, const sp& producer) { - auto displayId = compositionDisplay->getDisplayId(); DisplayDeviceCreationArgs creationArgs(this, displayToken, compositionDisplay); creationArgs.sequenceId = state.sequenceId; creationArgs.isSecure = state.isSecure; @@ -2390,26 +2391,26 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( creationArgs.connectionType = physical->type; } - const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked(); - creationArgs.isPrimary = isInternalDisplay; + if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) { + creationArgs.isPrimary = id == getInternalDisplayIdLocked(); - if (useColorManagement && displayId) { - std::vector modes = getHwComposer().getColorModes(*displayId); - for (ColorMode colorMode : modes) { - if (isWideColorMode(colorMode)) { - creationArgs.hasWideColorGamut = true; - } + if (useColorManagement) { + std::vector modes = getHwComposer().getColorModes(*id); + for (ColorMode colorMode : modes) { + if (isWideColorMode(colorMode)) { + creationArgs.hasWideColorGamut = true; + } - std::vector renderIntents = - getHwComposer().getRenderIntents(*displayId, colorMode); - creationArgs.hwcColorModes.emplace(colorMode, renderIntents); + std::vector renderIntents = + getHwComposer().getRenderIntents(*id, colorMode); + creationArgs.hwcColorModes.emplace(colorMode, renderIntents); + } } } - if (displayId) { - getHwComposer().getHdrCapabilities(*displayId, &creationArgs.hdrCapabilities); - creationArgs.supportedPerFrameMetadata = - getHwComposer().getSupportedPerFrameMetadata(*displayId); + if (const auto id = HalDisplayId::tryCast(compositionDisplay->getId())) { + getHwComposer().getHdrCapabilities(*id, &creationArgs.hdrCapabilities); + creationArgs.supportedPerFrameMetadata = getHwComposer().getSupportedPerFrameMetadata(*id); } auto nativeWindowSurface = getFactory().createNativeWindowSurface(producer); @@ -2424,7 +2425,7 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( } creationArgs.physicalOrientation = - isInternalDisplay ? internalDisplayOrientation : ui::ROTATION_0; + creationArgs.isPrimary ? internalDisplayOrientation : ui::ROTATION_0; // virtual displays are always considered enabled creationArgs.initialPowerMode = state.isVirtual() ? hal::PowerMode::ON : hal::PowerMode::OFF; @@ -2446,8 +2447,8 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); if (!state.isVirtual()) { - LOG_ALWAYS_FATAL_IF(!displayId); - auto activeConfigId = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(*displayId)); + const auto physicalId = display->getPhysicalId(); + auto activeConfigId = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(physicalId)); display->setActiveConfig(activeConfigId); display->setDeviceProductInfo(state.physical->deviceProductInfo); } @@ -2497,6 +2498,7 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, builder.setLayerStackId(state.layerStack); builder.setPowerAdvisor(&mPowerAdvisor); builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays); + builder.setGpuVirtualDisplayIdGenerator(mGpuVirtualDisplayIdGenerator); builder.setName(state.displayName); const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); @@ -2506,11 +2508,13 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, sp bqConsumer; getFactory().createBufferQueue(&bqProducer, &bqConsumer, /*consumerIsSurfaceFlinger =*/false); - std::optional displayId = compositionDisplay->getId(); + DisplayId displayId = compositionDisplay->getId(); if (state.isVirtual()) { + const auto virtualId = VirtualDisplayId::tryCast(displayId); + LOG_FATAL_IF(!virtualId); sp vds = - new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, bqProducer, + new VirtualDisplaySurface(getHwComposer(), *virtualId, state.surface, bqProducer, bqConsumer, state.displayName); displaySurface = vds; @@ -2520,9 +2524,9 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, "adding a supported display, but rendering " "surface is provided (%p), ignoring it", state.surface.get()); - - LOG_ALWAYS_FATAL_IF(!displayId); - displaySurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer, + const auto physicalId = PhysicalDisplayId::tryCast(displayId); + LOG_FATAL_IF(!physicalId); + displaySurface = new FramebufferSurface(getHwComposer(), *physicalId, bqConsumer, maxGraphicsWidth, maxGraphicsHeight); producer = bqProducer; } @@ -2532,8 +2536,7 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, displaySurface, producer); mDisplays.emplace(displayToken, display); if (!state.isVirtual()) { - LOG_FATAL_IF(!displayId); - dispatchDisplayHotplugEvent(static_cast(*displayId), true); + dispatchDisplayHotplugEvent(display->getPhysicalId(), true); } if (display->isPrimary()) { @@ -2543,13 +2546,9 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, void SurfaceFlinger::processDisplayRemoved(const wp& displayToken) { if (const auto display = getDisplayDeviceLocked(displayToken)) { - // Save display ID before disconnecting. - const auto displayId = display->getId(); display->disconnect(); - if (!display->isVirtual()) { - LOG_FATAL_IF(!displayId); - dispatchDisplayHotplugEvent(static_cast(*displayId), false); + dispatchDisplayHotplugEvent(display->getPhysicalId(), false); } } @@ -2825,7 +2824,7 @@ void SurfaceFlinger::commitInputWindowCommands() { void SurfaceFlinger::updateCursorAsync() { compositionengine::CompositionRefreshArgs refreshArgs; for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { - if (display->getId()) { + if (HalDisplayId::tryCast(display->getId())) { refreshArgs.outputs.push_back(display->getCompositionDisplay()); } } @@ -4111,10 +4110,8 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: return; } - const auto displayId = display->getId(); - LOG_ALWAYS_FATAL_IF(!displayId); - - ALOGD("Setting power mode %d on display %s", mode, to_string(*displayId).c_str()); + const auto displayId = display->getPhysicalId(); + ALOGD("Setting power mode %d on display %s", mode, to_string(displayId).c_str()); const hal::PowerMode currentMode = display->getPowerMode(); if (mode == currentMode) { @@ -4131,9 +4128,9 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) { ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno)); } - getHwComposer().setPowerMode(*displayId, mode); + getHwComposer().setPowerMode(displayId, mode); if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) { - getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState); + getHwComposer().setVsyncEnabled(displayId, mHWCVsyncPendingState); mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, vsyncPeriod); } @@ -4152,14 +4149,14 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: } // Make sure HWVsync is disabled before turning off the display - getHwComposer().setVsyncEnabled(*displayId, hal::Vsync::DISABLE); + getHwComposer().setVsyncEnabled(displayId, hal::Vsync::DISABLE); - getHwComposer().setPowerMode(*displayId, mode); + getHwComposer().setPowerMode(displayId, mode); mVisibleRegionsDirty = true; // from this point on, SF will stop drawing on this display } else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) { // Update display while dozing - getHwComposer().setPowerMode(*displayId, mode); + getHwComposer().setPowerMode(displayId, mode); if (display->isPrimary() && currentMode == hal::PowerMode::DOZE_SUSPEND) { mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, vsyncPeriod); @@ -4170,10 +4167,10 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: mScheduler->disableHardwareVsync(true); mScheduler->onScreenReleased(mAppConnectionHandle); } - getHwComposer().setPowerMode(*displayId, mode); + getHwComposer().setPowerMode(displayId, mode); } else { ALOGE("Attempting to set unknown power mode: %d\n", mode); - getHwComposer().setPowerMode(*displayId, mode); + getHwComposer().setPowerMode(displayId, mode); } if (display->isPrimary()) { @@ -4182,7 +4179,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON); } - ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str()); + ALOGD("Finished setting power mode %d on display %s", mode, to_string(displayId).c_str()); } void SurfaceFlinger::setPowerMode(const sp& displayToken, int mode) { @@ -4441,12 +4438,11 @@ void SurfaceFlinger::dumpBufferingStats(std::string& result) const { void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const { for (const auto& [token, display] : mDisplays) { - const auto displayId = display->getId(); + const auto displayId = PhysicalDisplayId::tryCast(display->getId()); if (!displayId) { continue; } - const auto hwcDisplayId = - getHwComposer().fromPhysicalDisplayId(static_cast(*displayId)); + const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId); if (!hwcDisplayId) { continue; } @@ -4499,7 +4495,7 @@ void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { // TODO: print out if wide-color mode is active or not for (const auto& [token, display] : mDisplays) { - const auto displayId = display->getId(); + const auto displayId = PhysicalDisplayId::tryCast(display->getId()); if (!displayId) { continue; } @@ -4713,7 +4709,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co * HWC layer minidump */ for (const auto& [token, display] : mDisplays) { - const auto displayId = display->getId(); + const auto displayId = HalDisplayId::tryCast(display->getId()); if (!displayId) { continue; } @@ -5232,18 +5228,12 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r // Inject a hotplug connected event for the primary display. This will deallocate and // reallocate the display state including framebuffers. case 1037: { - const auto token = getInternalDisplayToken(); - - sp display; + std::optional hwcId; { Mutex::Autolock lock(mStateLock); - display = getDisplayDeviceLocked(token); + hwcId = getHwComposer().getInternalHwcDisplayId(); } - const auto hwcId = - getHwComposer().fromPhysicalDisplayId(PhysicalDisplayId(*display->getId())); - onHotplugReceived(getBE().mComposerSequenceId, *hwcId, hal::Connection::CONNECTED); - return NO_ERROR; } } @@ -5850,16 +5840,14 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal( // as well. For now, just call directly to setActiveConfigWithConstraints but ideally // it should go thru setDesiredActiveConfig, similar to primary display. ALOGV("setAllowedDisplayConfigsInternal for non-primary display"); - const auto displayId = display->getId(); - LOG_ALWAYS_FATAL_IF(!displayId); + const auto displayId = display->getPhysicalId(); hal::VsyncPeriodChangeConstraints constraints; constraints.desiredTimeNanos = systemTime(); constraints.seamlessRequired = false; hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0}; - if (getHwComposer().setActiveConfigWithConstraints(*displayId, - policy->defaultConfig.value(), + if (getHwComposer().setActiveConfigWithConstraints(displayId, policy->defaultConfig.value(), constraints, &timeline) < 0) { return BAD_VALUE; } @@ -5869,11 +5857,9 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal( display->setActiveConfig(policy->defaultConfig); const nsecs_t vsyncPeriod = getHwComposer() - .getConfigs(*displayId)[policy->defaultConfig.value()] + .getConfigs(displayId)[policy->defaultConfig.value()] ->getVsyncPeriod(); - mScheduler->onNonPrimaryDisplayConfigChanged(mAppConnectionHandle, - static_cast( - *display->getId()), + mScheduler->onNonPrimaryDisplayConfigChanged(mAppConnectionHandle, displayId, policy->defaultConfig, vsyncPeriod); return NO_ERROR; } @@ -5905,8 +5891,8 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal( const nsecs_t vsyncPeriod = mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveConfig()) .getVsyncPeriod(); - mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, - static_cast(*display->getId()), + const auto physicalId = display->getPhysicalId(); + mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, physicalId, display->getActiveConfig(), vsyncPeriod); toggleKernelIdleTimer(); @@ -5997,11 +5983,9 @@ status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp& display } else if (display->isVirtual()) { return INVALID_OPERATION; } else { - const auto displayId = display->getId(); - LOG_FATAL_IF(!displayId); - - *outDefaultConfig = getHwComposer().getActiveConfigIndex(*displayId); - auto vsyncPeriod = getHwComposer().getActiveConfig(*displayId)->getVsyncPeriod(); + const auto displayId = display->getPhysicalId(); + *outDefaultConfig = getHwComposer().getActiveConfigIndex(displayId); + auto vsyncPeriod = getHwComposer().getActiveConfig(displayId)->getVsyncPeriod(); *outPrimaryRefreshRateMin = 1e9f / vsyncPeriod; *outPrimaryRefreshRateMax = 1e9f / vsyncPeriod; *outAppRequestRefreshRateMin = 1e9f / vsyncPeriod; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 0fd17d19d2..981c60df92 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -52,6 +52,7 @@ #include "DisplayDevice.h" #include "DisplayHardware/HWC2.h" #include "DisplayHardware/PowerAdvisor.h" +#include "DisplayIdGenerator.h" #include "Effects/Daltonizer.h" #include "FrameTracker.h" #include "LayerVector.h" @@ -945,8 +946,8 @@ private: return it != mPhysicalDisplayTokens.end() ? it->second : nullptr; } - std::optional getPhysicalDisplayIdLocked(const sp& displayToken) const - REQUIRES(mStateLock) { + std::optional getPhysicalDisplayIdLocked( + const sp& displayToken) const REQUIRES(mStateLock) { for (const auto& [id, token] : mPhysicalDisplayTokens) { if (token == displayToken) { return id; @@ -1109,6 +1110,8 @@ private: std::unordered_map> mPhysicalDisplayTokens GUARDED_BY(mStateLock); + RandomDisplayIdGenerator mGpuVirtualDisplayIdGenerator; + std::unordered_map> mLayersByLocalBinderToken GUARDED_BY(mStateLock); // don't use a lock for these, we don't care diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 6f1f1f2f55..a4a60d504c 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -39,6 +39,7 @@ cc_test { "CompositionTest.cpp", "DispSyncSourceTest.cpp", "DisplayIdentificationTest.cpp", + "DisplayIdGeneratorTest.cpp", "DisplayTransactionTest.cpp", "EventThreadTest.cpp", "FrameTimelineTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp new file mode 100644 index 0000000000..be7609a1a0 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp @@ -0,0 +1,82 @@ +/* + * 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 "DisplayIdGenerator.h" + +namespace android { + +template +void testNextId(DisplayIdGenerator& generator) { + constexpr int kNumIds = 5; + std::vector ids; + for (int i = 0; i < kNumIds; i++) { + const auto id = generator.nextId(); + ASSERT_TRUE(id); + ids.push_back(*id); + } + + // All IDs should be different. + for (size_t i = 0; i < kNumIds; i++) { + for (size_t j = i + 1; j < kNumIds; j++) { + EXPECT_NE(ids[i], ids[j]); + } + } +} + +TEST(DisplayIdGeneratorTest, nextIdGpuVirtual) { + RandomDisplayIdGenerator generator; + testNextId(generator); +} + +TEST(DisplayIdGeneratorTest, nextIdHalVirtual) { + RandomDisplayIdGenerator generator; + testNextId(generator); +} + +TEST(DisplayIdGeneratorTest, markUnused) { + constexpr size_t kMaxIdsCount = 5; + RandomDisplayIdGenerator generator(kMaxIdsCount); + + const auto id = generator.nextId(); + EXPECT_TRUE(id); + + for (int i = 1; i < kMaxIdsCount; i++) { + EXPECT_TRUE(generator.nextId()); + } + + EXPECT_FALSE(generator.nextId()); + + generator.markUnused(*id); + EXPECT_TRUE(generator.nextId()); +} + +TEST(DisplayIdGeneratorTest, maxIdsCount) { + constexpr size_t kMaxIdsCount = 5; + RandomDisplayIdGenerator generator(kMaxIdsCount); + + for (int i = 0; i < kMaxIdsCount; i++) { + EXPECT_TRUE(generator.nextId()); + } + + EXPECT_FALSE(generator.nextId()); +} + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index b750d6b39b..a81d2168de 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -338,9 +338,9 @@ template struct PhysicalDisplayIdType {}; template -using VirtualDisplayIdType = std::integral_constant; +using HalVirtualDisplayIdType = std::integral_constant; -struct NoDisplayId {}; +struct GpuVirtualDisplayIdType {}; template struct IsPhysicalDisplayId : std::bool_constant {}; @@ -353,7 +353,7 @@ struct DisplayIdGetter; template struct DisplayIdGetter> { - static std::optional get() { + static PhysicalDisplayId get() { if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) { return PhysicalDisplayId::fromPort(static_cast(PhysicalDisplay::PRIMARY) ? LEGACY_DISPLAY_TYPE_PRIMARY @@ -363,19 +363,18 @@ struct DisplayIdGetter> { const auto info = parseDisplayIdentificationData(PhysicalDisplay::PORT, PhysicalDisplay::GET_IDENTIFICATION_DATA()); - return info ? std::make_optional(info->id) : std::nullopt; + return info ? info->id : PhysicalDisplayId::fromPort(PhysicalDisplay::PORT); } }; template -struct DisplayIdGetter> { - // TODO(b/160679868) Use VirtualDisplayId - static std::optional get() { return PhysicalDisplayId{displayId}; } +struct DisplayIdGetter> { + static HalVirtualDisplayId get() { return HalVirtualDisplayId(displayId); } }; template <> -struct DisplayIdGetter { - static std::optional get() { return {}; } +struct DisplayIdGetter { + static GpuVirtualDisplayId get() { return GpuVirtualDisplayId(0); } }; template @@ -396,7 +395,7 @@ struct HwcDisplayIdGetter { constexpr HWDisplayId HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID = 1010; template -struct HwcDisplayIdGetter> { +struct HwcDisplayIdGetter> { static constexpr std::optional value = HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID; }; @@ -407,8 +406,8 @@ struct HwcDisplayIdGetter> { // DisplayIdType can be: // 1) PhysicalDisplayIdType<...> for generated ID of physical display backed by HWC. -// 2) VirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC. -// 3) NoDisplayId for virtual display without HWC backing. +// 2) HalVirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC. +// 3) GpuVirtualDisplayIdType for virtual display without HWC backing. template struct DisplayVariant { @@ -440,17 +439,36 @@ struct DisplayVariant { static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) { auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder(); - if (auto displayId = DISPLAY_ID::get()) { + if (auto displayId = PhysicalDisplayId::tryCast(DISPLAY_ID::get())) { ceDisplayArgs.setPhysical({*displayId, DisplayConnectionType::Internal}); } else { + // We turn off the use of HwcVirtualDisplays, to prevent Composition Engine + // from calling into HWComposer. This way all virtual displays will get + // a GpuVirtualDisplayId, even if we are in the HwcVirtualDisplayVariant. + // In this case we later override it by calling display.setDisplayIdForTesting(). ceDisplayArgs.setUseHwcVirtualDisplays(false); + + GpuVirtualDisplayId desiredDisplayId = GpuVirtualDisplayId::tryCast(DISPLAY_ID::get()) + .value_or(GpuVirtualDisplayId(0)); + + ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId()) + .WillByDefault(Return(desiredDisplayId)); + + auto& generator = test->mFlinger.gpuVirtualDisplayIdGenerator(); + ceDisplayArgs.setGpuVirtualDisplayIdGenerator(generator); } - ceDisplayArgs.setPixels({WIDTH, HEIGHT}).setPowerAdvisor(&test->mPowerAdvisor).build(); + ceDisplayArgs.setPixels({WIDTH, HEIGHT}).setPowerAdvisor(&test->mPowerAdvisor); auto compositionDisplay = compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), ceDisplayArgs.build()); + if (HalVirtualDisplayId::tryCast(DISPLAY_ID::get())) { + // CompositionEngine has assigned a placeholder GpuVirtualDisplayId and we need to + // override it with the correct HalVirtualDisplayId. + compositionDisplay->setDisplayIdForTesting(DISPLAY_ID::get()); + } + auto injector = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, CONNECTION_TYPE::value, HWC_DISPLAY_ID_OPT::value, static_cast(PRIMARY)); @@ -532,8 +550,8 @@ struct HwcDisplayVariant { // Called by tests to inject a HWC display setup static void injectHwcDisplayWithNoDefaultCapabilities(DisplayTransactionTest* test) { const auto displayId = DisplayVariant::DISPLAY_ID::get(); - ASSERT_TRUE(displayId); - FakeHwcDisplayInjector(*displayId, HWC_DISPLAY_TYPE, + ASSERT_FALSE(GpuVirtualDisplayId::tryCast(displayId)); + FakeHwcDisplayInjector(displayId, HWC_DISPLAY_TYPE, static_cast(DisplayVariant::PRIMARY)) .setHwcDisplayId(HWC_DISPLAY_ID) .setWidth(DisplayVariant::WIDTH) @@ -559,7 +577,7 @@ struct HwcDisplayVariant { ::testing::UnitTest::GetInstance()->current_test_info(); auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() - .setPhysical({*DisplayVariant::DISPLAY_ID::get(), + .setPhysical({DisplayVariant::DISPLAY_ID::get(), PhysicalDisplay::CONNECTION_TYPE}) .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT}) .setIsSecure(static_cast(DisplayVariant::SECURE)) @@ -686,10 +704,11 @@ constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0; template struct NonHwcVirtualDisplayVariant - : DisplayVariant { - using Base = DisplayVariant; + using Base = + DisplayVariant; static void injectHwcDisplay(DisplayTransactionTest*) {} @@ -698,12 +717,17 @@ struct NonHwcVirtualDisplayVariant const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); + ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId()) + .WillByDefault(Return(Base::DISPLAY_ID::get())); + auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() .setPixels({Base::WIDTH, Base::HEIGHT}) .setIsSecure(static_cast(Base::SECURE)) .setPowerAdvisor(&test->mPowerAdvisor) .setName(std::string("Injected display for ") + test_info->test_case_name() + "." + test_info->name()) + .setGpuVirtualDisplayIdGenerator( + test->mFlinger.gpuVirtualDisplayIdGenerator()) .build(); return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), @@ -725,13 +749,13 @@ constexpr uint32_t GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY = GRALLOC_USAGE_HW_COMPOSER template struct HwcVirtualDisplayVariant - : DisplayVariant, width, height, Critical::FALSE, Async::TRUE, + : DisplayVariant, width, height, Critical::FALSE, Async::TRUE, secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>, HwcDisplayVariant, width, height, Critical::FALSE, - Async::TRUE, secure, Primary::FALSE, + DisplayVariant, width, height, + Critical::FALSE, Async::TRUE, secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>> { - using Base = DisplayVariant, width, height, Critical::FALSE, + using Base = DisplayVariant, width, height, Critical::FALSE, Async::TRUE, secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER>; using Self = HwcVirtualDisplayVariant; @@ -740,6 +764,14 @@ struct HwcVirtualDisplayVariant const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); + // In order to prevent compostition engine calling into HWComposer, we + // 1. turn off the use of HWC virtual displays, + // 2. provide a GpuVirtualDisplayIdGenerator which always returns some fake ID + // 3. override the ID by calling setDisplayIdForTesting() + + ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId()) + .WillByDefault(Return(GpuVirtualDisplayId(0))); + auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() .setUseHwcVirtualDisplays(false) .setPixels({Base::WIDTH, Base::HEIGHT}) @@ -747,6 +779,8 @@ struct HwcVirtualDisplayVariant .setPowerAdvisor(&test->mPowerAdvisor) .setName(std::string("Injected display for ") + test_info->test_case_name() + "." + test_info->name()) + .setGpuVirtualDisplayIdGenerator( + test->mFlinger.gpuVirtualDisplayIdGenerator()) .build(); auto compositionDisplay = @@ -755,8 +789,9 @@ struct HwcVirtualDisplayVariant compositionDisplay->setDisplayIdForTesting(Base::DISPLAY_ID::get()); // Insert display data so that the HWC thinks it created the virtual display. - if (const auto displayId = Base::DISPLAY_ID::get()) { - test->mFlinger.mutableHwcDisplayData().try_emplace(*displayId); + if (const auto displayId = Base::DISPLAY_ID::get(); + HalVirtualDisplayId::tryCast(displayId)) { + test->mFlinger.mutableHwcDisplayData().try_emplace(displayId); } return compositionDisplay; @@ -1776,13 +1811,11 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { DisplayDeviceState state; if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) { - const auto displayId = Case::Display::DISPLAY_ID::get(); + const auto displayId = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get()); ASSERT_TRUE(displayId); const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value; ASSERT_TRUE(hwcDisplayId); - state.physical = {.id = static_cast(*displayId), - .type = *connectionType, - .hwcDisplayId = *hwcDisplayId}; + state.physical = {.id = *displayId, .type = *connectionType, .hwcDisplayId = *hwcDisplayId}; } state.isSecure = static_cast(Case::Display::SECURE); @@ -1954,11 +1987,11 @@ void HandleTransactionLockedTest::verifyDisplayIsConnected(const sp& di std::optional expectedPhysical; if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) { - const auto displayId = Case::Display::DISPLAY_ID::get(); + const auto displayId = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get()); ASSERT_TRUE(displayId); const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value; ASSERT_TRUE(hwcDisplayId); - expectedPhysical = {.id = static_cast(*displayId), + expectedPhysical = {.id = *displayId, .type = *connectionType, .hwcDisplayId = *hwcDisplayId}; } @@ -1983,9 +2016,9 @@ void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() { // SF should have a display token. const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(displayId); - ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 1); - auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[*displayId]; + ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); + ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1); + auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[displayId]; verifyDisplayIsConnected(displayToken); } @@ -2088,8 +2121,8 @@ void HandleTransactionLockedTest::processesHotplugDisconnectCommon() { // SF should not have a display token. const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(displayId); - ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 0); + ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); + ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0); // The existing token should have been removed verifyDisplayIsNotConnected(existing.token()); @@ -2174,8 +2207,8 @@ TEST_F(HandleTransactionLockedTest, processesHotplugConnectThenDisconnectPrimary // SF should not have a display token. const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(displayId); - ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 0); + ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); + ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0); } TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) { @@ -2213,9 +2246,9 @@ TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary // The existing token should have been removed verifyDisplayIsNotConnected(existing.token()); const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(displayId); - ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 1); - EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[*displayId]); + ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); + ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1); + EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[displayId]); // A new display should be connected in its place @@ -2349,8 +2382,8 @@ TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) { // A virtual display is set up but is removed from the current state. const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(displayId); - mFlinger.mutableHwcDisplayData().try_emplace(*displayId); + ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId)); + mFlinger.mutableHwcDisplayData().try_emplace(displayId); Case::Display::injectHwcDisplay(this); auto existing = Case::Display::makeFakeExistingDisplayInjector(this); existing.inject(); @@ -3485,8 +3518,8 @@ TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay // Insert display data so that the HWC thinks it created the virtual display. const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(displayId); - mFlinger.mutableHwcDisplayData().try_emplace(*displayId); + ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId)); + mFlinger.mutableHwcDisplayData().try_emplace(displayId); // A virtual display device is set up Case::Display::injectHwcDisplay(this); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 37f159c66c..0ea5ddc2ba 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -40,6 +40,7 @@ #include "SurfaceInterceptor.h" #include "TestableScheduler.h" #include "mock/DisplayHardware/MockDisplay.h" +#include "mock/MockDisplayIdGenerator.h" namespace android { @@ -171,6 +172,9 @@ public: SurfaceFlinger* flinger() { return mFlinger.get(); } TestableScheduler* scheduler() { return mScheduler; } + mock::DisplayIdGenerator& gpuVirtualDisplayIdGenerator() { + return mGpuVirtualDisplayIdGenerator; + } // Extend this as needed for accessing SurfaceFlinger private (and public) // functions. @@ -463,7 +467,8 @@ public: static constexpr hal::HWConfigId DEFAULT_ACTIVE_CONFIG = 0; static constexpr hal::PowerMode DEFAULT_POWER_MODE = hal::PowerMode::ON; - FakeHwcDisplayInjector(DisplayId displayId, hal::DisplayType hwcDisplayType, bool isPrimary) + FakeHwcDisplayInjector(HalDisplayId displayId, hal::DisplayType hwcDisplayType, + bool isPrimary) : mDisplayId(displayId), mHwcDisplayType(hwcDisplayType), mIsPrimary(isPrimary) {} auto& setHwcDisplayId(hal::HWDisplayId displayId) { @@ -536,14 +541,16 @@ public: flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = std::move(display); if (mHwcDisplayType == hal::DisplayType::PHYSICAL) { - flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, mDisplayId); + const auto physicalId = PhysicalDisplayId::tryCast(mDisplayId); + LOG_ALWAYS_FATAL_IF(!physicalId); + flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, *physicalId); (mIsPrimary ? flinger->mutableInternalHwcDisplayId() : flinger->mutableExternalHwcDisplayId()) = mHwcDisplayId; } } private: - const DisplayId mDisplayId; + const HalDisplayId mDisplayId; const hal::DisplayType mHwcDisplayType; const bool mIsPrimary; @@ -635,10 +642,10 @@ public: DisplayDeviceState state; if (const auto type = mCreationArgs.connectionType) { LOG_ALWAYS_FATAL_IF(!displayId); + const auto physicalId = PhysicalDisplayId::tryCast(*displayId); + LOG_ALWAYS_FATAL_IF(!physicalId); LOG_ALWAYS_FATAL_IF(!mHwcDisplayId); - state.physical = {.id = static_cast(*displayId), - .type = *type, - .hwcDisplayId = *mHwcDisplayId}; + state.physical = {.id = *physicalId, .type = *type, .hwcDisplayId = *mHwcDisplayId}; } state.isSecure = mCreationArgs.isSecure; @@ -672,6 +679,7 @@ private: sp mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization); TestableScheduler* mScheduler = nullptr; Hwc2::mock::Display mDisplay; + mock::DisplayIdGenerator mGpuVirtualDisplayIdGenerator; }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp index 0780af1f26..251ab36d14 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp @@ -20,17 +20,13 @@ #include "mock/DisplayHardware/MockComposer.h" -namespace android { -namespace Hwc2 { -namespace mock { +namespace android::Hwc2::mock { // Explicit default instantiation is recommended. Composer::Composer() = default; Composer::~Composer() = default; -} // namespace mock -} // namespace Hwc2 -} // namespace android +} // namespace android::Hwc2::mock // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index cd9b87a60e..1ba3c0f56e 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -24,8 +24,7 @@ namespace android { class GraphicBuffer; -namespace Hwc2 { -namespace mock { +namespace Hwc2::mock { using android::hardware::graphics::common::V1_0::ColorTransform; using android::hardware::graphics::common::V1_0::Transform; @@ -140,6 +139,5 @@ public: MOCK_METHOD2(getClientTargetProperty, Error(Display, IComposerClient::ClientTargetProperty*)); }; -} // namespace mock -} // namespace Hwc2 +} // namespace Hwc2::mock } // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.cpp index 2ec37c1e76..c9788afbe4 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.cpp +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.cpp @@ -16,14 +16,10 @@ #include "mock/DisplayHardware/MockDisplay.h" -namespace android { -namespace Hwc2 { -namespace mock { +namespace android::Hwc2::mock { // Explicit default instantiation is recommended. Display::Display() = default; Display::~Display() = default; -} // namespace mock -} // namespace Hwc2 -} // namespace android \ No newline at end of file +} // namespace android::Hwc2::mock \ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h index fe99e77158..a96d9dbe2a 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h @@ -22,9 +22,7 @@ using android::HWC2::Layer; -namespace android { -namespace Hwc2 { -namespace mock { +namespace android::Hwc2::mock { namespace hal = android::hardware::graphics::composer::hal; @@ -98,6 +96,4 @@ public: MOCK_CONST_METHOD0(isVsyncPeriodSwitchSupported, bool()); }; -} // namespace mock -} // namespace Hwc2 -} // namespace android +} // namespace android::Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.cpp index 8be707750b..1ba38a822a 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.cpp +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.cpp @@ -16,14 +16,10 @@ #include "MockPowerAdvisor.h" -namespace android { -namespace Hwc2 { -namespace mock { +namespace android::Hwc2::mock { // Explicit default instantiation is recommended. PowerAdvisor::PowerAdvisor() = default; PowerAdvisor::~PowerAdvisor() = default; -} // namespace mock -} // namespace Hwc2 -} // namespace android +} // namespace android::Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h index e22d0cf74c..7450b5dfa4 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h @@ -20,9 +20,7 @@ #include "DisplayHardware/PowerAdvisor.h" -namespace android { -namespace Hwc2 { -namespace mock { +namespace android::Hwc2::mock { class PowerAdvisor : public android::Hwc2::PowerAdvisor { public: @@ -34,6 +32,4 @@ public: MOCK_METHOD0(notifyDisplayUpdateImminent, void()); }; -} // namespace mock -} // namespace Hwc2 -} // namespace android +} // namespace android::Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockDisplayIdGenerator.h b/services/surfaceflinger/tests/unittests/mock/MockDisplayIdGenerator.h new file mode 100644 index 0000000000..cfc37ea8d9 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/MockDisplayIdGenerator.h @@ -0,0 +1,36 @@ +/* + * 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 "DisplayIdGenerator.h" + +namespace android::mock { + +template +class DisplayIdGenerator : public android::DisplayIdGenerator { +public: + // Explicit default instantiation is recommended. + DisplayIdGenerator() = default; + virtual ~DisplayIdGenerator() = default; + + MOCK_METHOD0(nextId, std::optional()); + MOCK_METHOD1(markUnused, void(T)); +}; + +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.cpp b/services/surfaceflinger/tests/unittests/mock/MockEventThread.cpp index 408cd35f29..302dc01b23 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.cpp +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.cpp @@ -16,12 +16,10 @@ #include "mock/MockEventThread.h" -namespace android { -namespace mock { +namespace android::mock { // Explicit default instantiation is recommended. EventThread::EventThread() = default; EventThread::~EventThread() = default; -} // namespace mock -} // namespace android +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index eefdec18aa..b4594c183d 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -20,8 +20,7 @@ #include "Scheduler/EventThread.h" -namespace android { -namespace mock { +namespace android::mock { class EventThread : public android::EventThread { public: @@ -47,5 +46,4 @@ public: MOCK_METHOD0(getEventThreadConnectionCount, size_t()); }; -} // namespace mock -} // namespace android +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp index 358dfdb856..417dcb0869 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp +++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp @@ -16,12 +16,10 @@ #include "mock/MockFrameTracer.h" -namespace android { -namespace mock { +namespace android::mock { // Explicit default instantiation is recommended. FrameTracer::FrameTracer() = default; FrameTracer::~FrameTracer() = default; -} // namespace mock -} // namespace android +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h index f768b8114d..305cb1c7c6 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h @@ -20,8 +20,7 @@ #include "FrameTracer/FrameTracer.h" -namespace android { -namespace mock { +namespace android::mock { class FrameTracer : public android::FrameTracer { public: @@ -39,5 +38,4 @@ public: MOCK_METHOD0(miniDump, std::string()); }; -} // namespace mock -} // namespace android +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp index 7e925b94ee..0a0e7b5861 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp +++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp @@ -20,15 +20,13 @@ #include "mock/MockSurfaceInterceptor.h" -namespace android { -namespace mock { +namespace android::mock { // Explicit default instantiation is recommended. SurfaceInterceptor::SurfaceInterceptor() = default; SurfaceInterceptor::~SurfaceInterceptor() = default; -} // namespace mock -} // namespace android +} // namespace android::mock // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h index 03a04a95bc..b085027397 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h +++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h @@ -20,8 +20,7 @@ #include "SurfaceInterceptor.h" -namespace android { -namespace mock { +namespace android::mock { class SurfaceInterceptor : public android::SurfaceInterceptor { public: @@ -48,5 +47,4 @@ public: MOCK_METHOD1(saveVSyncEvent, void(nsecs_t)); }; -} // namespace mock -} // namespace android +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.cpp b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.cpp index d686939b3a..f8e76b290b 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.cpp +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.cpp @@ -16,12 +16,10 @@ #include "mock/MockTimeStats.h" -namespace android { -namespace mock { +namespace android::mock { // Explicit default instantiation is recommended. TimeStats::TimeStats() = default; TimeStats::~TimeStats() = default; -} // namespace mock -} // namespace android +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h index 4186e2b574..ff37ec8018 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h @@ -20,8 +20,7 @@ #include "TimeStats/TimeStats.h" -namespace android { -namespace mock { +namespace android::mock { class TimeStats : public android::TimeStats { public: @@ -59,5 +58,4 @@ public: MOCK_METHOD1(setPresentFenceGlobal, void(const std::shared_ptr&)); }; -} // namespace mock -} // namespace android +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.cpp b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.cpp index 8a181232d8..bcccae5b1b 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.cpp +++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.cpp @@ -15,15 +15,11 @@ */ #include "mock/MockVSyncTracker.h" -#include -using namespace std::chrono_literals; -namespace android { -namespace mock { +namespace android::mock { // Explicit default instantiation is recommended. VSyncTracker::VSyncTracker() = default; VSyncTracker::~VSyncTracker() = default; -} // namespace mock -} // namespace android +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h index 1d87546a19..94d99665ce 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h +++ b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h @@ -20,8 +20,7 @@ #include "Scheduler/VsyncController.h" -namespace android { -namespace mock { +namespace android::mock { class VsyncController : public android::scheduler::VsyncController { public: @@ -36,5 +35,4 @@ public: MOCK_CONST_METHOD1(dump, void(std::string&)); }; -} // namespace mock -} // namespace android +} // namespace android::mock -- cgit v1.2.3-59-g8ed1b From 916b036726e2e82f769405d25bf6b8248572246c Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Tue, 6 Oct 2020 13:53:03 -0700 Subject: SurfaceControl: Remove setOverrideScalingMode Following recent frameworks/base changes there are no callers. Bug: 161937501 Test: Existing tests pass Change-Id: I1a39d30ebd70a0b0cb430a6d1ae48086c3e1806e --- cmds/surfacereplayer/proto/src/trace.proto | 5 --- cmds/surfacereplayer/replayer/Replayer.cpp | 10 ----- cmds/surfacereplayer/replayer/Replayer.h | 2 - .../replayer/trace_creator/trace_creator.py | 9 ----- libs/gui/LayerState.cpp | 7 ---- libs/gui/SurfaceComposerClient.cpp | 29 ------------- libs/gui/include/gui/LayerState.h | 3 +- libs/gui/include/gui/SurfaceComposerClient.h | 5 --- services/surfaceflinger/BufferLayer.cpp | 4 -- services/surfaceflinger/BufferLayer.h | 3 +- services/surfaceflinger/BufferQueueLayer.cpp | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 5 ++- services/surfaceflinger/BufferStateLayer.h | 2 +- services/surfaceflinger/Layer.cpp | 7 ---- services/surfaceflinger/Layer.h | 3 -- services/surfaceflinger/LayerRejecter.cpp | 5 +-- services/surfaceflinger/LayerRejecter.h | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 5 --- services/surfaceflinger/SurfaceInterceptor.cpp | 12 ------ services/surfaceflinger/SurfaceInterceptor.h | 2 - .../tests/LayerRenderTypeTransaction_test.cpp | 47 ---------------------- services/surfaceflinger/tests/LayerUpdate_test.cpp | 15 +++++-- .../tests/SurfaceInterceptor_test.cpp | 27 ------------- .../tests/fakehwc/SFFakeHwc_test.cpp | 28 ------------- 24 files changed, 23 insertions(+), 217 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto index 6c3b79b2b9..bbf4f8dd38 100644 --- a/cmds/surfacereplayer/proto/src/trace.proto +++ b/cmds/surfacereplayer/proto/src/trace.proto @@ -41,7 +41,6 @@ message SurfaceChange { LayerChange layer = 5; CropChange crop = 6; MatrixChange matrix = 8; - OverrideScalingModeChange override_scaling_mode = 9; TransparentRegionHintChange transparent_region_hint = 10; LayerStackChange layer_stack = 11; HiddenFlagChange hidden_flag = 12; @@ -95,10 +94,6 @@ message MatrixChange { required float dtdy = 4; } -message OverrideScalingModeChange { - required int32 override_scaling_mode = 1; -} - message TransparentRegionHintChange { repeated Rectangle region = 1; } diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index 86e4f5d773..c1868016d0 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -387,10 +387,6 @@ status_t Replayer::doSurfaceTransaction( case SurfaceChange::SurfaceChangeCase::kMatrix: setMatrix(transaction, change.id(), change.matrix()); break; - case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode: - setOverrideScalingMode(transaction, change.id(), - change.override_scaling_mode()); - break; case SurfaceChange::SurfaceChangeCase::kTransparentRegionHint: setTransparentRegionHint(transaction, change.id(), change.transparent_region_hint()); @@ -525,12 +521,6 @@ void Replayer::setMatrix(SurfaceComposerClient::Transaction& t, t.setMatrix(mLayers[id], mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy()); } -void Replayer::setOverrideScalingMode(SurfaceComposerClient::Transaction& t, - layer_id id, const OverrideScalingModeChange& osmc) { - ALOGV("Layer %d: Setting Override Scaling Mode -- mode=%d", id, osmc.override_scaling_mode()); - t.setOverrideScalingMode(mLayers[id], osmc.override_scaling_mode()); -} - void Replayer::setTransparentRegionHint(SurfaceComposerClient::Transaction& t, layer_id id, const TransparentRegionHintChange& trhc) { ALOGV("Setting Transparent Region Hint"); diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h index 95857e1e5b..e439718bd6 100644 --- a/cmds/surfacereplayer/replayer/Replayer.h +++ b/cmds/surfacereplayer/replayer/Replayer.h @@ -98,8 +98,6 @@ class Replayer { layer_id id, const BackgroundBlurRadiusChange& cc); void setMatrix(SurfaceComposerClient::Transaction& t, layer_id id, const MatrixChange& mc); - void setOverrideScalingMode(SurfaceComposerClient::Transaction& t, - layer_id id, const OverrideScalingModeChange& osmc); void setTransparentRegionHint(SurfaceComposerClient::Transaction& t, layer_id id, const TransparentRegionHintChange& trgc); void setLayerStack(SurfaceComposerClient::Transaction& t, diff --git a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py index d63d97f6b4..58bfbf3c43 100644 --- a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py +++ b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py @@ -69,7 +69,6 @@ def transaction_menu(): print ("5. Crop Change") print ("6. Final Crop Change") print ("7. Matrix Change") - print ("8. Override Scaling Mode Change") print ("9. Transparent Region Hint Change") print ("10. Layer Stack Change") print ("11. Hidden Flag Change") @@ -128,9 +127,6 @@ def transaction(increment): change.matrix.dtdx,\ change.matrix.dsdy,\ change.matrix.dtdy = layer() - elif option == 8: - change.override_scaling_mode.override_scaling_mode \ - = override_scaling_mode() elif option == 9: for rect in transparent_region_hint(): new = increment.transparent_region_hint.region.add() @@ -227,11 +223,6 @@ def matrix(): return float(dsdx) -def override_scaling_mode(): - mode = input("Enter override scaling mode: ") - - return int(mode) - def transparent_region_hint(): num = input("Enter number of rectangles in region: ") diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index bde73bab2e..ed5ad3f4ce 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -44,7 +44,6 @@ layer_state_t::layer_state_t() cornerRadius(0.0f), backgroundBlurRadius(0), barrierFrameNumber(0), - overrideScalingMode(-1), transform(0), transformToDisplayInverse(false), crop(Rect::INVALID_RECT), @@ -86,7 +85,6 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, barrierSurfaceControl_legacy); SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, reparentSurfaceControl); SAFE_PARCEL(output.writeUint64, barrierFrameNumber); - SAFE_PARCEL(output.writeInt32, overrideScalingMode); SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, relativeLayerSurfaceControl); SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, parentSurfaceControlForChild); SAFE_PARCEL(output.writeFloat, color.r); @@ -176,7 +174,6 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &barrierSurfaceControl_legacy); SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &reparentSurfaceControl); SAFE_PARCEL(input.readUint64, &barrierFrameNumber); - SAFE_PARCEL(input.readInt32, &overrideScalingMode); SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &relativeLayerSurfaceControl); SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &parentSurfaceControlForChild); @@ -381,10 +378,6 @@ void layer_state_t::merge(const layer_state_t& other) { barrierSurfaceControl_legacy = other.barrierSurfaceControl_legacy; barrierFrameNumber = other.barrierFrameNumber; } - if (other.what & eOverrideScalingModeChanged) { - what |= eOverrideScalingModeChanged; - overrideScalingMode = other.overrideScalingMode; - } if (other.what & eReparentChildren) { what |= eReparentChildren; reparentSurfaceControl = other.reparentSurfaceControl; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 0068ccfc65..105969bd42 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1353,35 +1353,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachCh return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverrideScalingMode( - const sp& sc, int32_t overrideScalingMode) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - - switch (overrideScalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: - case -1: - break; - default: - ALOGE("unknown scaling mode: %d", - overrideScalingMode); - mStatus = BAD_VALUE; - return *this; - } - - s->what |= layer_state_t::eOverrideScalingModeChanged; - s->overrideScalingMode = overrideScalingMode; - - registerSurfaceControlForCallback(sc); - return *this; -} - #ifndef NO_INPUT SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo( const sp& sc, diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index fed0ef3565..1d282c8dc5 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -94,7 +94,7 @@ struct layer_state_t { eLayerStackChanged = 0x00000080, eCropChanged_legacy = 0x00000100, eDeferTransaction_legacy = 0x00000200, - eOverrideScalingModeChanged = 0x00000400, + /* was ScalingModeChanged, now available 0x00000400, */ eShadowRadiusChanged = 0x00000800, eReparentChildren = 0x00001000, eDetachChildren = 0x00002000, @@ -163,7 +163,6 @@ struct layer_state_t { sp barrierSurfaceControl_legacy; sp reparentSurfaceControl; uint64_t barrierFrameNumber; - int32_t overrideScalingMode; sp relativeLayerSurfaceControl; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 277060fed0..ce1a0a5f30 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -501,11 +501,6 @@ public: // Sometimes the WindowManager needs to extend their lifetime slightly // in order to perform an exit animation or prevent flicker. Transaction& detachChildren(const sp& sc); - // Set an override scaling mode as documented in - // the override scaling mode will take precedence over any client - // specified scaling mode. -1 will clear the override scaling mode. - Transaction& setOverrideScalingMode(const sp& sc, - int32_t overrideScalingMode); #ifndef NO_INPUT Transaction& setInputWindowInfo(const sp& sc, const InputWindowInfo& info); diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index c77298e161..9c3fdbb405 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -527,10 +527,6 @@ bool BufferLayer::hasReadyFrame() const { } uint32_t BufferLayer::getEffectiveScalingMode() const { - if (mOverrideScalingMode >= 0) { - return mOverrideScalingMode; - } - return mBufferInfo.mScaleMode; } diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 1cd753b65b..e6a0f81622 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -94,8 +94,7 @@ public: bool hasReadyFrame() const override; - // Returns the current scaling mode, unless mOverrideScalingMode - // is set, in which case, it returns mOverrideScalingMode + // Returns the current scaling mode uint32_t getEffectiveScalingMode() const override; // Calls latchBuffer if the buffer has a frame queued and then releases the buffer. diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 0863a22659..ec828d435b 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -239,7 +239,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t bool queuedBuffer = false; const int32_t layerId = getSequence(); LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions, - getProducerStickyTransform() != 0, mName, mOverrideScalingMode, + getProducerStickyTransform() != 0, mName, getTransformToDisplayInverse()); if (isRemovedFromCurrentState()) { diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 361c1f3f98..9a4571805d 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -48,7 +48,6 @@ const std::array BufferStateLayer::IDENTITY_MATRIX{ BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) : BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) { - mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; mCurrentState.dataspace = ui::Dataspace::V0_SRGB; } @@ -681,6 +680,10 @@ void BufferStateLayer::gatherBufferInfo() { mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId); } +uint32_t BufferStateLayer::getEffectiveScalingMode() const { + return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; +} + Rect BufferStateLayer::computeCrop(const State& s) { if (s.crop.isEmpty() && s.buffer) { return s.buffer->getBounds(); diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index c13f5e8252..4773286e44 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -92,7 +92,6 @@ public: return false; } bool setCrop_legacy(const Rect& /*crop*/) override { return false; } - bool setOverrideScalingMode(int32_t /*overrideScalingMode*/) override { return false; } void deferTransactionUntil_legacy(const sp& /*barrierHandle*/, uint64_t /*frameNumber*/) override {} void deferTransactionUntil_legacy(const sp& /*barrierLayer*/, @@ -110,6 +109,7 @@ public: bool fenceHasSignaled() const override; bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override; bool onPreComposition(nsecs_t refreshStartTime) override; + uint32_t getEffectiveScalingMode() const override; protected: void gatherBufferInfo() override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index a79cbe455a..5616bbac59 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1295,13 +1295,6 @@ bool Layer::setCrop_legacy(const Rect& crop) { return true; } -bool Layer::setOverrideScalingMode(int32_t scalingMode) { - if (scalingMode == mOverrideScalingMode) return false; - mOverrideScalingMode = scalingMode; - setTransactionFlags(eTransactionNeeded); - return true; -} - bool Layer::setMetadata(const LayerMetadata& data) { if (!mCurrentState.metadata.merge(data, true /* eraseEmpty */)) return false; mCurrentState.sequence++; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 02593d57ef..51e392aa30 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -341,7 +341,6 @@ public: // // The first set of geometry functions are controlled by the scaling mode, described // in window.h. The scaling mode may be set by the client, as it submits buffers. - // This value may be overriden through SurfaceControl, with setOverrideScalingMode. // // Put simply, if our scaling mode is SCALING_MODE_FREEZE, then // matrix updates will not be applied while a resize is pending @@ -399,7 +398,6 @@ public: virtual void deferTransactionUntil_legacy(const sp& barrierHandle, uint64_t frameNumber); virtual void deferTransactionUntil_legacy(const sp& barrierLayer, uint64_t frameNumber); - virtual bool setOverrideScalingMode(int32_t overrideScalingMode); virtual bool setMetadata(const LayerMetadata& data); virtual void setChildrenDrawingParent(const sp&); virtual bool reparent(const sp& newParentHandle); @@ -1003,7 +1001,6 @@ protected: bool mIsActiveBufferUpdatedForGpu = true; // We encode unset as -1. - int32_t mOverrideScalingMode{-1}; std::atomic mCurrentFrameNumber{0}; // Whether filtering is needed b/c of the drawingstate bool mNeedsFiltering{false}; diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp index e6c8654cbf..053b7f741e 100644 --- a/services/surfaceflinger/LayerRejecter.cpp +++ b/services/surfaceflinger/LayerRejecter.cpp @@ -29,13 +29,12 @@ namespace android { LayerRejecter::LayerRejecter(Layer::State& front, Layer::State& current, bool& recomputeVisibleRegions, bool stickySet, const std::string& name, - int32_t overrideScalingMode, bool transformToDisplayInverse) + bool transformToDisplayInverse) : mFront(front), mCurrent(current), mRecomputeVisibleRegions(recomputeVisibleRegions), mStickyTransformSet(stickySet), mName(name), - mOverrideScalingMode(overrideScalingMode), mTransformToDisplayInverse(transformToDisplayInverse) {} bool LayerRejecter::reject(const sp& buf, const BufferItem& item) { @@ -59,7 +58,7 @@ bool LayerRejecter::reject(const sp& buf, const BufferItem& item) } } - int actualScalingMode = mOverrideScalingMode >= 0 ? mOverrideScalingMode : item.mScalingMode; + int actualScalingMode = item.mScalingMode; bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE; if (mFront.active_legacy != mFront.requested_legacy) { if (isFixedSize || diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h index fb5c750571..4981f451d9 100644 --- a/services/surfaceflinger/LayerRejecter.h +++ b/services/surfaceflinger/LayerRejecter.h @@ -24,7 +24,7 @@ namespace android { class LayerRejecter : public BufferLayerConsumer::BufferRejecter { public: LayerRejecter(Layer::State& front, Layer::State& current, bool& recomputeVisibleRegions, - bool stickySet, const std::string& name, int32_t overrideScalingMode, + bool stickySet, const std::string& name, bool transformToDisplayInverse); virtual bool reject(const sp&, const BufferItem&); @@ -35,7 +35,6 @@ private: bool& mRecomputeVisibleRegions; const bool mStickyTransformSet; const std::string& mName; - const int32_t mOverrideScalingMode; const bool mTransformToDisplayInverse; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7edbcaa6b3..2f66d5b9e7 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3703,11 +3703,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( if (what & layer_state_t::eDetachChildren) { layer->detachChildren(); } - if (what & layer_state_t::eOverrideScalingModeChanged) { - layer->setOverrideScalingMode(s.overrideScalingMode); - // We don't trigger a traversal here because if no other state is - // changed, we don't want this to cause any more work - } if (what & layer_state_t::eTransformChanged) { if (layer->setTransform(s.transform)) flags |= eTraversalNeeded; } diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index da58d4ea4d..2d5566f42a 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -145,7 +145,6 @@ void SurfaceInterceptor::addInitialSurfaceStateLocked(Increment* increment, layer->mCurrentState.barrierLayer_legacy.promote(), layer->mCurrentState.barrierFrameNumber); } - addOverrideScalingModeLocked(transaction, layerId, layer->getEffectiveScalingMode()); addFlagsLocked(transaction, layerId, layer->mCurrentState.flags, layer_state_t::eLayerHidden | layer_state_t::eLayerOpaque | layer_state_t::eLayerSecure); @@ -376,14 +375,6 @@ void SurfaceInterceptor::addDeferTransactionLocked(Transaction* transaction, int deferTransaction->set_frame_number(frameNumber); } -void SurfaceInterceptor::addOverrideScalingModeLocked(Transaction* transaction, - int32_t layerId, int32_t overrideScalingMode) -{ - SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); - OverrideScalingModeChange* overrideChange(change->mutable_override_scaling_mode()); - overrideChange->set_override_scaling_mode(overrideScalingMode); -} - void SurfaceInterceptor::addReparentLocked(Transaction* transaction, int32_t layerId, int32_t parentId) { SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); @@ -474,9 +465,6 @@ void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction, } addDeferTransactionLocked(transaction, layerId, otherLayer, state.barrierFrameNumber); } - if (state.what & layer_state_t::eOverrideScalingModeChanged) { - addOverrideScalingModeLocked(transaction, layerId, state.overrideScalingMode); - } if (state.what & layer_state_t::eReparent) { auto parentHandle = (state.parentSurfaceControlForChild) ? state.parentSurfaceControlForChild->getHandle() diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h index 9ac189a492..97ff547547 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -167,8 +167,6 @@ private: int32_t backgroundBlurRadius); void addDeferTransactionLocked(Transaction* transaction, int32_t layerId, const sp& layer, uint64_t frameNumber); - void addOverrideScalingModeLocked(Transaction* transaction, int32_t layerId, - int32_t overrideScalingMode); void addSurfaceChangesLocked(Transaction* transaction, const layer_state_t& state); void addTransactionLocked(Increment* increment, const Vector& stateUpdates, const DefaultKeyedVector, DisplayDeviceState>& displays, diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index 494728953b..52e1a4d967 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -179,19 +179,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) { } } -TEST_P(LayerRenderTypeTransactionTest, SetSizeWithScaleToWindow_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // setSize is immediate with SCALE_TO_WINDOW, unlike setPosition - Transaction() - .setSize(layer, 64, 64) - .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) - .apply(); - getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED); -} - TEST_P(LayerRenderTypeTransactionTest, CreateLayer_BufferState) { uint32_t transformHint = ui::Transform::ROT_INVALID; sp layer; @@ -950,40 +937,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithResize_BufferQueue) { } } -TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition - Transaction() - .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f) - .setSize(layer, 64, 64) - .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) - .apply(); - getScreenCapture()->expectColor(Rect(0, 0, 128, 128), Color::RED); -} - -TEST_P(LayerRenderTypeTransactionTest, SetOverrideScalingModeBasic_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE)); - - // XXX SCALE_CROP is not respected; calling setSize and - // setOverrideScalingMode in separate transactions does not work - // (b/69315456) - Transaction() - .setSize(layer, 64, 16) - .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) - .apply(); - { - SCOPED_TRACE("SCALE_TO_WINDOW"); - getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN, - Color::BLUE, Color::WHITE, true /* filtered */); - } -} - TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) { sp layer; ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index 38da0b195b..0cafd001ff 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -566,7 +566,10 @@ TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) { } asTransaction([&](Transaction& t) { - t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + mFGSurfaceControl->getSurface()->setScalingMode( + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + // Resubmit buffer with new scaling mode + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); // We cause scaling by 2. t.setSize(mFGSurfaceControl, 128, 128); }); @@ -673,7 +676,10 @@ TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) { } asTransaction([&](Transaction& t) { - t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + mFGSurfaceControl->getSurface()->setScalingMode( + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + // Resubmit buffer with new scaling mode + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); // Set a scaling by 2. t.setSize(mFGSurfaceControl, 128, 128); }); @@ -705,7 +711,10 @@ TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) { // Change the size of the foreground to 128 * 64 so we can test rotation as well. asTransaction([&](Transaction& t) { - t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + mFGSurfaceControl->getSurface()->setScalingMode( + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + // Resubmit buffer with new scaling mode + TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); t.setSize(mFGSurfaceControl, 128, 64); }); sp s = mFGSurfaceControl->getSurface(); diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 104d919216..a5a569bb0f 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -39,7 +39,6 @@ using SurfaceChange = surfaceflinger::SurfaceChange; using Trace = surfaceflinger::Trace; using Increment = surfaceflinger::Increment; -constexpr int32_t SCALING_UPDATE = 1; constexpr uint32_t BUFFER_UPDATES = 18; constexpr uint32_t LAYER_UPDATE = INT_MAX - 2; constexpr uint32_t SIZE_UPDATE = 134; @@ -221,7 +220,6 @@ public: void cornerRadiusUpdate(Transaction&); void backgroundBlurRadiusUpdate(Transaction&); void matrixUpdate(Transaction&); - void overrideScalingModeUpdate(Transaction&); void transparentRegionHintUpdate(Transaction&); void layerStackUpdate(Transaction&); void hiddenFlagUpdate(Transaction&); @@ -371,10 +369,6 @@ void SurfaceInterceptorTest::matrixUpdate(Transaction& t) { t.setMatrix(mBGSurfaceControl, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2); } -void SurfaceInterceptorTest::overrideScalingModeUpdate(Transaction& t) { - t.setOverrideScalingMode(mBGSurfaceControl, SCALING_UPDATE); -} - void SurfaceInterceptorTest::transparentRegionHintUpdate(Transaction& t) { Region region(CROP_UPDATE); t.setTransparentRegionHint(mBGSurfaceControl, region); @@ -439,7 +433,6 @@ void SurfaceInterceptorTest::runAllUpdates() { runInTransaction(&SurfaceInterceptorTest::layerUpdate); runInTransaction(&SurfaceInterceptorTest::cropUpdate); runInTransaction(&SurfaceInterceptorTest::matrixUpdate); - runInTransaction(&SurfaceInterceptorTest::overrideScalingModeUpdate); runInTransaction(&SurfaceInterceptorTest::transparentRegionHintUpdate); runInTransaction(&SurfaceInterceptorTest::layerStackUpdate); runInTransaction(&SurfaceInterceptorTest::hiddenFlagUpdate); @@ -561,17 +554,6 @@ bool SurfaceInterceptorTest::matrixUpdateFound(const SurfaceChange& change, bool return foundMatrix; } -bool SurfaceInterceptorTest::scalingModeUpdateFound(const SurfaceChange& change, - bool foundScalingMode) { - bool hasScalingUpdate(change.override_scaling_mode().override_scaling_mode() == SCALING_UPDATE); - if (hasScalingUpdate && !foundScalingMode) { - foundScalingMode = true; - } else if (hasScalingUpdate && foundScalingMode) { - [] () { FAIL(); }(); - } - return foundScalingMode; -} - bool SurfaceInterceptorTest::transparentRegionHintUpdateFound(const SurfaceChange& change, bool foundTransparentRegion) { auto traceRegion = change.transparent_region_hint().region(0); @@ -727,9 +709,6 @@ bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace, case SurfaceChange::SurfaceChangeCase::kMatrix: foundUpdate = matrixUpdateFound(change, foundUpdate); break; - case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode: - foundUpdate = scalingModeUpdateFound(change, foundUpdate); - break; case SurfaceChange::SurfaceChangeCase::kTransparentRegionHint: foundUpdate = transparentRegionHintUpdateFound(change, foundUpdate); break; @@ -780,7 +759,6 @@ void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) { ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kLayer)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kCrop)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kMatrix)); - ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kOverrideScalingMode)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kTransparentRegionHint)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kLayerStack)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kHiddenFlag)); @@ -915,11 +893,6 @@ TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) { captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix); } -TEST_F(SurfaceInterceptorTest, InterceptOverrideScalingModeUpdateWorks) { - captureTest(&SurfaceInterceptorTest::overrideScalingModeUpdate, - SurfaceChange::SurfaceChangeCase::kOverrideScalingMode); -} - TEST_F(SurfaceInterceptorTest, InterceptTransparentRegionHintUpdateWorks) { captureTest(&SurfaceInterceptorTest::transparentRegionHintUpdate, SurfaceChange::SurfaceChangeCase::kTransparentRegionHint); diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index 07c558f342..1606f2241e 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -1691,30 +1691,6 @@ protected: EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame())); } - void Test_InheritNonTransformScalingFromParent() { - { - TransactionScope ts(*Base::sFakeComposer); - ts.show(mChild); - ts.setPosition(mChild, 0, 0); - ts.setPosition(Base::mFGSurfaceControl, 0, 0); - } - - { - TransactionScope ts(*Base::sFakeComposer); - ts.setOverrideScalingMode(Base::mFGSurfaceControl, - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - // We cause scaling by 2. - ts.setSize(Base::mFGSurfaceControl, 128, 128); - } - - auto referenceFrame = Base::mBaseFrame; - referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128}; - referenceFrame[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 64.f}; - referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20}; - referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 10.f, 10.f}; - EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame())); - } - // Regression test for b/37673612 void Test_ChildrenWithParentBufferTransform() { { @@ -1823,10 +1799,6 @@ TEST_F(ChildLayerTest_2_1, DISABLED_DetachChildrenDifferentClient) { Test_DetachChildrenDifferentClient(); } -TEST_F(ChildLayerTest_2_1, DISABLED_InheritNonTransformScalingFromParent) { - Test_InheritNonTransformScalingFromParent(); -} - // Regression test for b/37673612 TEST_F(ChildLayerTest_2_1, DISABLED_ChildrenWithParentBufferTransform) { Test_ChildrenWithParentBufferTransform(); -- cgit v1.2.3-59-g8ed1b From e7f79c51ec0d00bc79d9e4f017a56cdb627667bb Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 29 Oct 2020 14:45:03 -0700 Subject: Check if the buffer is actually being scaled instead of only checking scaling mode BufferStateLayers have a default scale to window scaling mode which means the layers would be set use texture filtering regardless of the buffer size. This was breaking some pixel by pixel screenshot comparison tests. Instead check if the buffer size, after applying any buffer transforms, matches the layer size. Test: android.view.inputmethod.cts.FocusHandlingTest#testNonFocusablePopupWindowDoesNotAffectImeVisibility Change-Id: I90b05187a2e22834a99d3690095293fa37118734 --- services/surfaceflinger/BufferLayer.cpp | 8 ++++++-- services/surfaceflinger/BufferLayer.h | 4 ++++ services/surfaceflinger/BufferStateLayer.cpp | 25 +++++++++++++++++++++++++ services/surfaceflinger/BufferStateLayer.h | 2 ++ 4 files changed, 37 insertions(+), 2 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 9c3fdbb405..d302f987b1 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -204,8 +204,8 @@ std::optional BufferLayer::prepareCli layer.frameNumber = mCurrentFrameNumber; layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0; - // TODO: we could be more subtle with isFixedSize() - const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize(); + const bool useFiltering = + targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering(); // Query the texture matrix given our current filtering mode. float textureMatrix[16]; @@ -822,6 +822,10 @@ void BufferLayer::setTransformHint(ui::Transform::RotationFlags displayTransform } } +bool BufferLayer::bufferNeedsFiltering() const { + return isFixedSize(); +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index e6a0f81622..deaf8461e8 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -115,6 +115,10 @@ public: ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; } + // Returns true if the transformed buffer size does not match the layer size and we need + // to apply filtering. + virtual bool bufferNeedsFiltering() const; + protected: struct BufferInfo { nsecs_t mDesiredPresentTime; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 6f344c721a..f85151449b 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -744,6 +744,31 @@ Layer::RoundedCornerState BufferStateLayer::getRoundedCornerState() const { static_cast(s.active.transform.ty() + s.active.h)), radius); } + +bool BufferStateLayer::bufferNeedsFiltering() const { + const State& s(getDrawingState()); + if (!s.buffer) { + return false; + } + + uint32_t bufferWidth = s.buffer->width; + uint32_t bufferHeight = s.buffer->height; + + // Undo any transformations on the buffer and return the result. + if (s.transform & ui::Transform::ROT_90) { + std::swap(bufferWidth, bufferHeight); + } + + if (s.transformToDisplayInverse) { + uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); + if (invTransform & ui::Transform::ROT_90) { + std::swap(bufferWidth, bufferHeight); + } + } + + const Rect layerSize{getBounds()}; + return layerSize.width() != bufferWidth || layerSize.height() != bufferHeight; +} } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 4773286e44..104a13be71 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -143,6 +143,8 @@ private: bool willPresentCurrentTransaction() const; + bool bufferNeedsFiltering() const override; + static const std::array IDENTITY_MATRIX; std::unique_ptr mTextureImage; -- cgit v1.2.3-59-g8ed1b From 0bb6a47f5264571690d57c609f0e945086dba9b1 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 12 Oct 2020 10:22:13 -0700 Subject: SurfaceFlinger: throttle applications based on uid Add the ability for SurfaceFlinger to be able to throttle down to a divider of the refresh rate (i.e. for 30/45 for 90Hz) Change-Id: I6bfd6f43ee1f30e771a136c558d8ae9a6d7fbe0f Test: Manually via 1039 SF backdoor Bug: 170502573 Bug: 169270763 Bug: 169271059 --- services/surfaceflinger/BufferLayer.cpp | 9 +++ services/surfaceflinger/Scheduler/EventThread.cpp | 31 ++++++-- services/surfaceflinger/Scheduler/EventThread.h | 10 ++- .../Scheduler/RefreshRateConfigs.cpp | 32 ++++++++ .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 9 +++ services/surfaceflinger/Scheduler/Scheduler.cpp | 18 ++++- services/surfaceflinger/Scheduler/Scheduler.h | 4 + .../surfaceflinger/Scheduler/VSyncPredictor.cpp | 83 +++++++++++++++++--- services/surfaceflinger/Scheduler/VSyncPredictor.h | 35 ++++++--- services/surfaceflinger/Scheduler/VSyncTracker.h | 8 ++ services/surfaceflinger/SurfaceFlinger.cpp | 9 ++- .../tests/unittests/CompositionTest.cpp | 6 +- .../tests/unittests/DisplayTransactionTest.cpp | 6 +- .../tests/unittests/EventThreadTest.cpp | 89 +++++++++++++++++++--- .../tests/unittests/RefreshRateConfigsTest.cpp | 28 +++++++ .../tests/unittests/RefreshRateSelectionTest.cpp | 6 +- .../tests/unittests/SchedulerTest.cpp | 2 +- .../tests/unittests/SetFrameRateTest.cpp | 6 +- .../tests/unittests/TransactionApplicationTest.cpp | 6 +- .../tests/unittests/VSyncDispatchRealtimeTest.cpp | 2 + .../unittests/VSyncDispatchTimerQueueTest.cpp | 1 + .../tests/unittests/VSyncPredictorTest.cpp | 75 ++++++++++++------ .../tests/unittests/VSyncReactorTest.cpp | 1 + .../tests/unittests/mock/MockVSyncTracker.h | 1 + 24 files changed, 395 insertions(+), 82 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index d302f987b1..fa75ffa403 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -393,6 +393,15 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) { ATRACE_CALL(); + // If this is not a valid vsync for the layer's uid, return and try again later + const bool isVsyncValidForUid = + mFlinger->mScheduler->isVsyncValid(expectedPresentTime, mOwnerUid); + if (!isVsyncValidForUid) { + ATRACE_NAME("!isVsyncValidForUid"); + mFlinger->setTransactionFlags(eTraversalNeeded); + return false; + } + bool refreshRequired = latchSidebandStream(recomputeVisibleRegions); if (refreshRequired) { diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index bf2a5090af..bf5be4790d 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -31,6 +31,8 @@ #include +#include + #include #include @@ -123,11 +125,12 @@ DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId, } // namespace -EventThreadConnection::EventThreadConnection(EventThread* eventThread, +EventThreadConnection::EventThreadConnection(EventThread* eventThread, uid_t callingUid, ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged) : resyncCallback(std::move(resyncCallback)), mConfigChanged(configChanged), + mOwnerUid(callingUid), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {} @@ -170,10 +173,12 @@ namespace impl { EventThread::EventThread(std::unique_ptr vsyncSource, android::frametimeline::TokenManager* tokenManager, - InterceptVSyncsCallback interceptVSyncsCallback) + InterceptVSyncsCallback interceptVSyncsCallback, + ThrottleVsyncCallback throttleVsyncCallback) : mVSyncSource(std::move(vsyncSource)), mTokenManager(tokenManager), mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)), + mThrottleVsyncCallback(std::move(throttleVsyncCallback)), mThreadName(mVSyncSource->getName()) { mVSyncSource->setCallback(this); @@ -216,8 +221,9 @@ void EventThread::setDuration(std::chrono::nanoseconds workDuration, sp EventThread::createEventConnection( ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged) const { - return new EventThreadConnection(const_cast(this), std::move(resyncCallback), - configChanged); + return new EventThreadConnection(const_cast(this), + IPCThreadState::self()->getCallingUid(), + std::move(resyncCallback), configChanged); } status_t EventThread::registerDisplayEventConnection(const sp& connection) { @@ -443,6 +449,11 @@ void EventThread::threadMain(std::unique_lock& lock) { bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, const sp& connection) const { + const auto throttleVsync = [&] { + return mThrottleVsyncCallback && + mThrottleVsyncCallback(event.vsync.expectedVSyncTimestamp, connection->mOwnerUid); + }; + switch (event.header.type) { case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: return true; @@ -458,12 +469,22 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, case VSyncRequest::SingleSuppressCallback: connection->vsyncRequest = VSyncRequest::None; return false; - case VSyncRequest::Single: + case VSyncRequest::Single: { + if (throttleVsync()) { + return false; + } connection->vsyncRequest = VSyncRequest::SingleSuppressCallback; return true; + } case VSyncRequest::Periodic: + if (throttleVsync()) { + return false; + } return true; default: + // We don't throttle vsync if the app set a vsync request rate + // since there is no easy way to do that and this is a very + // rare case return event.vsync.count % vsyncPeriod(connection->vsyncRequest) == 0; } diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index e42ca05450..2e2d98950e 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -81,7 +81,7 @@ public: class EventThreadConnection : public BnDisplayEventConnection { public: - EventThreadConnection(EventThread*, ResyncCallback, + EventThreadConnection(EventThread*, uid_t callingUid, ResyncCallback, ISurfaceComposer::ConfigChanged configChanged); virtual ~EventThreadConnection(); @@ -98,6 +98,8 @@ public: const ISurfaceComposer::ConfigChanged mConfigChanged = ISurfaceComposer::ConfigChanged::eConfigChangedSuppress; + const uid_t mOwnerUid; + private: virtual void onFirstRef(); EventThread* const mEventThread; @@ -143,9 +145,10 @@ namespace impl { class EventThread : public android::EventThread, private VSyncSource::Callback { public: using InterceptVSyncsCallback = std::function; + using ThrottleVsyncCallback = std::function; - EventThread(std::unique_ptr, frametimeline::TokenManager*, - InterceptVSyncsCallback); + EventThread(std::unique_ptr, frametimeline::TokenManager*, InterceptVSyncsCallback, + ThrottleVsyncCallback); ~EventThread(); sp createEventConnection( @@ -196,6 +199,7 @@ private: frametimeline::TokenManager* const mTokenManager; const InterceptVSyncsCallback mInterceptVSyncsCallback; + const ThrottleVsyncCallback mThrottleVsyncCallback; const char* const mThreadName; std::thread mThread; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 7ab49a97ab..7d97e72fbb 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -625,4 +625,36 @@ RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction return RefreshRateConfigs::KernelIdleTimerAction::TurnOn; } +void RefreshRateConfigs::setPreferredRefreshRateForUid(uid_t uid, float refreshRateHz) { + if (refreshRateHz > 0 && refreshRateHz < 1) { + return; + } + + std::lock_guard lock(mLock); + if (refreshRateHz != 0) { + mPreferredRefreshRateForUid[uid] = refreshRateHz; + } else { + mPreferredRefreshRateForUid.erase(uid); + } +} + +int RefreshRateConfigs::getRefreshRateDividerForUid(uid_t uid) const { + constexpr float kThreshold = 0.1f; + std::lock_guard lock(mLock); + + const auto iter = mPreferredRefreshRateForUid.find(uid); + if (iter == mPreferredRefreshRateForUid.end()) { + return 1; + } + + const auto refreshRateHz = iter->second; + const auto numPeriods = mCurrentRefreshRate->getFps() / refreshRateHz; + const auto numPeriodsRounded = std::round(numPeriods); + if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) { + return 1; + } + + return static_cast(numPeriods); +} + } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 280ed62426..5cf7d07a38 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -311,6 +311,13 @@ public: // refresh rates. KernelIdleTimerAction getIdleTimerAction() const; + // Stores the preferred refresh rate that an app should run at. + // refreshRate == 0 means no preference. + void setPreferredRefreshRateForUid(uid_t, float refreshRateHz) EXCLUDES(mLock); + + // Returns a divider for the current refresh rate + int getRefreshRateDividerForUid(uid_t) const EXCLUDES(mLock); + private: friend class RefreshRateConfigsTest; @@ -368,6 +375,8 @@ private: Policy mDisplayManagerPolicy GUARDED_BY(mLock); std::optional mOverridePolicy GUARDED_BY(mLock); + std::unordered_map mPreferredRefreshRateForUid GUARDED_BY(mLock); + // The min and max refresh rates supported by the device. // This will not change at runtime. const RefreshRate* mMinSupportedRefreshRate; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 7b8448f750..a14019eeb5 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -212,13 +212,26 @@ std::unique_ptr Scheduler::makePrimaryDispSyncSource( readyDuration, traceVsync, name); } +bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const { + const auto divider = mRefreshRateConfigs.getRefreshRateDividerForUid(uid); + if (divider <= 1) { + return true; + } + + return mVsyncSchedule.tracker->isVSyncInPhase(expectedVsyncTimestamp, divider); +} + Scheduler::ConnectionHandle Scheduler::createConnection( const char* connectionName, frametimeline::TokenManager* tokenManager, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, impl::EventThread::InterceptVSyncsCallback interceptCallback) { auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration); + auto throttleVsync = [this](nsecs_t expectedVsyncTimestamp, uid_t uid) { + return !isVsyncValid(expectedVsyncTimestamp, uid); + }; auto eventThread = std::make_unique(std::move(vsyncSource), tokenManager, - std::move(interceptCallback)); + std::move(interceptCallback), + std::move(throttleVsync)); return createConnection(std::move(eventThread)); } @@ -379,7 +392,8 @@ Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { auto eventThread = std::make_unique(std::move(vsyncSource), /*tokenManager=*/nullptr, - impl::EventThread::InterceptVSyncsCallback()); + impl::EventThread::InterceptVSyncsCallback(), + impl::EventThread::ThrottleVsyncCallback()); mInjectorConnectionHandle = createConnection(std::move(eventThread)); } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 47ce4a4dff..4c86d26a01 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -139,6 +139,10 @@ public: scheduler::VSyncDispatch& getVsyncDispatch() { return *mVsyncSchedule.dispatch; } + // Returns true if a given vsync timestamp is considered valid vsync + // for a given uid + bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const; + void dump(std::string&) const; void dump(ConnectionHandle, std::string&) const; void dumpVsync(std::string&) const; diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index e90edf77a2..75d1e6f132 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -27,6 +27,9 @@ #include #include +#undef LOG_TAG +#define LOG_TAG "VSyncPredictor" + namespace android::scheduler { using base::StringAppendF; @@ -66,7 +69,7 @@ bool VSyncPredictor::validate(nsecs_t timestamp) const { nsecs_t VSyncPredictor::currentPeriod() const { std::lock_guard lock(mMutex); - return std::get<0>(mRateMap.find(mIdealPeriod)->second); + return mRateMap.find(mIdealPeriod)->second.slope; } bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { @@ -118,7 +121,7 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { // normalizing to the oldest timestamp cuts down on error in calculating the intercept. auto const oldest_ts = *std::min_element(mTimestamps.begin(), mTimestamps.end()); auto it = mRateMap.find(mIdealPeriod); - auto const currentPeriod = std::get<0>(it->second); + auto const currentPeriod = it->second.slope; // TODO (b/144707443): its important that there's some precision in the mean of the ordinals // for the intercept calculation, so scale the ordinals by 1000 to continue // fixed point calculation. Explore expanding @@ -172,10 +175,8 @@ bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) { return true; } -nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { - std::lock_guard lock(mMutex); - - auto const [slope, intercept] = getVSyncPredictionModel(lock); +nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFromLocked(nsecs_t timePoint) const { + auto const [slope, intercept] = getVSyncPredictionModelLocked(); if (mTimestamps.empty()) { traceInt64If("VSP-mode", 1); @@ -210,13 +211,71 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { return prediction; } -std::tuple VSyncPredictor::getVSyncPredictionModel() const { +nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { + std::lock_guard lock(mMutex); + return nextAnticipatedVSyncTimeFromLocked(timePoint); +} + +/* + * Returns whether a given vsync timestamp is in phase with a vsync divider. + * For example, if the vsync timestamps are (0,16,32,48): + * isVSyncInPhase(0, 2) = true + * isVSyncInPhase(16, 2) = false + * isVSyncInPhase(32, 2) = true + */ +bool VSyncPredictor::isVSyncInPhase(nsecs_t timePoint, int divider) const { + struct VsyncError { + nsecs_t vsyncTimestamp; + float error; + + bool operator<(const VsyncError& other) const { return error < other.error; } + }; + + std::lock_guard lock(mMutex); + if (divider <= 1) { + return true; + } + + const nsecs_t period = mRateMap[mIdealPeriod].slope; + const nsecs_t justBeforeTimePoint = timePoint - period / 2; + const nsecs_t dividedPeriod = mIdealPeriod / divider; + + // If this is the first time we have asked about this divider with the + // current vsync period, it is considered in phase and we store the closest + // vsync timestamp + const auto knownTimestampIter = mRateDividerKnownTimestampMap.find(dividedPeriod); + if (knownTimestampIter == mRateDividerKnownTimestampMap.end()) { + const auto vsync = nextAnticipatedVSyncTimeFromLocked(justBeforeTimePoint); + mRateDividerKnownTimestampMap[dividedPeriod] = vsync; + return true; + } + + // Find the next N vsync timestamp where N is the divider. + // One of these vsyncs will be in phase. We return the one which is + // the most aligned with the last known in phase vsync + std::vector vsyncs(static_cast(divider)); + const nsecs_t knownVsync = knownTimestampIter->second; + nsecs_t point = justBeforeTimePoint; + for (size_t i = 0; i < divider; i++) { + const nsecs_t vsync = nextAnticipatedVSyncTimeFromLocked(point); + const auto numPeriods = static_cast(vsync - knownVsync) / (period * divider); + const auto error = std::abs(std::round(numPeriods) - numPeriods); + vsyncs[i] = {vsync, error}; + point = vsync + 1; + } + + const auto minVsyncError = std::min_element(vsyncs.begin(), vsyncs.end()); + mRateDividerKnownTimestampMap[dividedPeriod] = minVsyncError->vsyncTimestamp; + return std::abs(minVsyncError->vsyncTimestamp - timePoint) < period / 2; +} + +VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModel() const { std::lock_guard lock(mMutex); - return VSyncPredictor::getVSyncPredictionModel(lock); + const auto model = VSyncPredictor::getVSyncPredictionModelLocked(); + return {model.slope, model.intercept}; } -std::tuple VSyncPredictor::getVSyncPredictionModel( - std::lock_guard const&) const { +VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModelLocked() const { return mRateMap.find(mIdealPeriod)->second; } @@ -269,8 +328,8 @@ void VSyncPredictor::dump(std::string& result) const { for (const auto& [idealPeriod, periodInterceptTuple] : mRateMap) { StringAppendF(&result, "\t\tFor ideal period %.2fms: period = %.2fms, intercept = %" PRId64 "\n", - idealPeriod / 1e6f, std::get<0>(periodInterceptTuple) / 1e6f, - std::get<1>(periodInterceptTuple)); + idealPeriod / 1e6f, periodInterceptTuple.slope / 1e6f, + periodInterceptTuple.intercept); } } diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h index 5f2ec492b7..381cf81f5c 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.h +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h @@ -38,10 +38,10 @@ public: uint32_t outlierTolerancePercent); ~VSyncPredictor(); - bool addVsyncTimestamp(nsecs_t timestamp) final; - nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final; - nsecs_t currentPeriod() const final; - void resetModel() final; + bool addVsyncTimestamp(nsecs_t timestamp) final EXCLUDES(mMutex); + nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final EXCLUDES(mMutex); + nsecs_t currentPeriod() const final EXCLUDES(mMutex); + void resetModel() final EXCLUDES(mMutex); /* * Inform the model that the period is anticipated to change to a new value. @@ -50,16 +50,23 @@ public: * * \param [in] period The new period that should be used. */ - void setPeriod(nsecs_t period) final; + void setPeriod(nsecs_t period) final EXCLUDES(mMutex); /* Query if the model is in need of more samples to make a prediction. * \return True, if model would benefit from more samples, False if not. */ - bool needsMoreSamples() const final; + bool needsMoreSamples() const final EXCLUDES(mMutex); - std::tuple getVSyncPredictionModel() const; + struct Model { + nsecs_t slope; + nsecs_t intercept; + }; - void dump(std::string& result) const final; + VSyncPredictor::Model getVSyncPredictionModel() const EXCLUDES(mMutex); + + bool isVSyncInPhase(nsecs_t timePoint, int divider) const final EXCLUDES(mMutex); + + void dump(std::string& result) const final EXCLUDES(mMutex); private: VSyncPredictor(VSyncPredictor const&) = delete; @@ -76,13 +83,19 @@ private: std::mutex mutable 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); + + Model getVSyncPredictionModelLocked() const REQUIRES(mMutex); + + nsecs_t nextAnticipatedVSyncTimeFromLocked(nsecs_t timePoint) const REQUIRES(mMutex); nsecs_t mIdealPeriod GUARDED_BY(mMutex); std::optional mKnownTimestamp GUARDED_BY(mMutex); - std::unordered_map> mutable mRateMap GUARDED_BY(mMutex); + // Map between ideal vsync period and the calculated model + std::unordered_map mutable mRateMap GUARDED_BY(mMutex); + + // Map between the divided vsync period and the last known vsync timestamp + std::unordered_map mutable mRateDividerKnownTimestampMap GUARDED_BY(mMutex); size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0; std::vector mTimestamps GUARDED_BY(mMutex); diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h index 107c5400fe..2cd9b3df18 100644 --- a/services/surfaceflinger/Scheduler/VSyncTracker.h +++ b/services/surfaceflinger/Scheduler/VSyncTracker.h @@ -68,6 +68,14 @@ public: virtual bool needsMoreSamples() const = 0; + /* + * Checks if a vsync timestamp is in phase for a given divider. + * + * \param [in] timePoint A vsync timestamp + * \param [in] divider The divider to check for + */ + virtual bool isVSyncInPhase(nsecs_t timePoint, int divider) const = 0; + virtual void dump(std::string& result) const = 0; protected: diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index fde38c911e..1119fcefb1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4915,7 +4915,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } // Numbers from 1000 to 1038 are currently used for backdoors. The code // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1038) { + if (code >= 1000 && code <= 1039) { ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); return OK; } @@ -5280,6 +5280,13 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r mFrameTimeline->setMaxDisplayFrames(n); return NO_ERROR; } + case 1039: { + // The first parameter is the uid + n = data.readInt32(); + const float refreshRateHz = data.readFloat(); + mRefreshRateConfigs->setPreferredRefreshRateForUid(n, refreshRateHz); + } + return NO_ERROR; } } return err; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index a4f74495d0..091171266f 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -134,13 +134,15 @@ public: EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) .WillOnce(Return( - new EventThreadConnection(eventThread.get(), ResyncCallback(), + new EventThreadConnection(eventThread.get(), /*callingUid=*/0, + ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) .WillOnce(Return( - new EventThreadConnection(sfEventThread.get(), ResyncCallback(), + new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, + ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); auto vsyncController = std::make_unique(); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index db05d5a61f..f0311bdaab 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -70,12 +70,14 @@ DisplayTransactionTest::~DisplayTransactionTest() { void DisplayTransactionTest::injectMockScheduler() { EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*mEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(mEventThread, ResyncCallback(), + .WillOnce(Return(new EventThreadConnection(mEventThread, /*callingUid=*/0, + ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*mSFEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(mSFEventThread, ResyncCallback(), + .WillOnce(Return(new EventThreadConnection(mSFEventThread, /*callingUid=*/0, + ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); mFlinger.setupScheduler(std::unique_ptr(mVsyncController), diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index f680bdbf1b..3aafd456d9 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -59,9 +59,11 @@ class EventThreadTest : public testing::Test { protected: class MockEventThreadConnection : public EventThreadConnection { public: - MockEventThreadConnection(impl::EventThread* eventThread, ResyncCallback&& resyncCallback, + MockEventThreadConnection(impl::EventThread* eventThread, uid_t callingUid, + ResyncCallback&& resyncCallback, ISurfaceComposer::ConfigChanged configChanged) - : EventThreadConnection(eventThread, std::move(resyncCallback), configChanged) {} + : EventThreadConnection(eventThread, callingUid, std::move(resyncCallback), + configChanged) {} MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event)); }; @@ -73,7 +75,8 @@ protected: void createThread(std::unique_ptr); sp createConnection(ConnectionEventRecorder& recorder, - ISurfaceComposer::ConfigChanged configChanged); + ISurfaceComposer::ConfigChanged configChanged, + uid_t ownerUid = mConnectionUid); void expectVSyncSetEnabledCallReceived(bool expectedState); void expectVSyncSetDurationCallReceived(std::chrono::nanoseconds expectedDuration, @@ -89,6 +92,7 @@ protected: void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId, nsecs_t expectedVsyncPeriod); + void expectThrottleVsyncReceived(nsecs_t expectedTimestamp, uid_t); AsyncCallRecorder mVSyncSetEnabledCallRecorder; AsyncCallRecorder mVSyncSetCallbackCallRecorder; @@ -96,12 +100,18 @@ protected: mVSyncSetDurationCallRecorder; AsyncCallRecorder mResyncCallRecorder; AsyncCallRecorder mInterceptVSyncCallRecorder; + AsyncCallRecorder mThrottleVsyncCallRecorder; ConnectionEventRecorder mConnectionEventCallRecorder{0}; + ConnectionEventRecorder mThrottledConnectionEventCallRecorder{0}; MockVSyncSource* mVSyncSource; VSyncSource::Callback* mCallback = nullptr; std::unique_ptr mThread; sp mConnection; + sp mThrottledConnection; + + static constexpr uid_t mConnectionUid = 443; + static constexpr uid_t mThrottledConnectionUid = 177; }; EventThreadTest::EventThreadTest() { @@ -124,6 +134,9 @@ EventThreadTest::EventThreadTest() { createThread(std::move(vsyncSource)); mConnection = createConnection(mConnectionEventCallRecorder, ISurfaceComposer::eConfigChangedDispatch); + mThrottledConnection = + createConnection(mThrottledConnectionEventCallRecorder, + ISurfaceComposer::eConfigChangedDispatch, mThrottledConnectionUid); // A display must be connected for VSYNC events to be delivered. mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true); @@ -140,9 +153,15 @@ EventThreadTest::~EventThreadTest() { } void EventThreadTest::createThread(std::unique_ptr source) { + const auto throttleVsync = [&](nsecs_t expectedVsyncTimestamp, uid_t uid) { + mThrottleVsyncCallRecorder.getInvocable()(expectedVsyncTimestamp, uid); + return (uid == mThrottledConnectionUid); + }; + mThread = std::make_unique(std::move(source), /*tokenManager=*/nullptr, - mInterceptVSyncCallRecorder.getInvocable()); + mInterceptVSyncCallRecorder.getInvocable(), + throttleVsync); // EventThread should register itself as VSyncSource callback. mCallback = expectVSyncSetCallbackCallReceived(); @@ -150,10 +169,11 @@ void EventThreadTest::createThread(std::unique_ptr source) { } sp EventThreadTest::createConnection( - ConnectionEventRecorder& recorder, ISurfaceComposer::ConfigChanged configChanged) { + ConnectionEventRecorder& recorder, ISurfaceComposer::ConfigChanged configChanged, + uid_t ownerUid) { sp connection = - new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable(), - configChanged); + new MockEventThreadConnection(mThread.get(), ownerUid, + mResyncCallRecorder.getInvocable(), configChanged); EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable())); return connection; } @@ -183,6 +203,13 @@ void EventThreadTest::expectInterceptCallReceived(nsecs_t expectedTimestamp) { EXPECT_EQ(expectedTimestamp, std::get<0>(args.value())); } +void EventThreadTest::expectThrottleVsyncReceived(nsecs_t expectedTimestamp, uid_t uid) { + auto args = mThrottleVsyncCallRecorder.waitForCall(); + ASSERT_TRUE(args.has_value()); + EXPECT_EQ(expectedTimestamp, std::get<0>(args.value())); + EXPECT_EQ(uid, std::get<1>(args.value())); +} + void EventThreadTest::expectVsyncEventReceivedByConnection( const char* name, ConnectionEventRecorder& connectionEventRecorder, nsecs_t expectedTimestamp, unsigned expectedCount) { @@ -267,13 +294,15 @@ TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { // The interceptor should receive the event, as well as the connection. mCallback->onVSyncEvent(123, 456, 789); expectInterceptCallReceived(123); + expectThrottleVsyncReceived(456, mConnectionUid); expectVsyncEventReceivedByConnection(123, 1u); // Use the received callback to signal a second vsync event. - // The interceptor should receive the event, but the the connection should + // The interceptor should receive the event, but the connection should // not as it was only interested in the first. mCallback->onVSyncEvent(456, 123, 0); expectInterceptCallReceived(456); + EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value()); EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value()); // EventThread should also detect that at this point that it does not need @@ -323,16 +352,19 @@ TEST_F(EventThreadTest, setVsyncRateOnePostsAllEventsToThatConnection) { // interceptor, and the connection. mCallback->onVSyncEvent(123, 456, 789); expectInterceptCallReceived(123); + expectThrottleVsyncReceived(456, mConnectionUid); expectVsyncEventReceivedByConnection(123, 1u); // A second event should go to the same places. mCallback->onVSyncEvent(456, 123, 0); expectInterceptCallReceived(456); + expectThrottleVsyncReceived(123, mConnectionUid); expectVsyncEventReceivedByConnection(456, 2u); // A third event should go to the same places. mCallback->onVSyncEvent(789, 777, 111); expectInterceptCallReceived(789); + expectThrottleVsyncReceived(777, mConnectionUid); expectVsyncEventReceivedByConnection(789, 3u); } @@ -346,16 +378,19 @@ TEST_F(EventThreadTest, setVsyncRateTwoPostsEveryOtherEventToThatConnection) { mCallback->onVSyncEvent(123, 456, 789); expectInterceptCallReceived(123); EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value()); // The second event will be seen by the interceptor and the connection. mCallback->onVSyncEvent(456, 123, 0); expectInterceptCallReceived(456); expectVsyncEventReceivedByConnection(456, 2u); + EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value()); // The third event will be seen by the interceptor, and not the connection. mCallback->onVSyncEvent(789, 777, 744); expectInterceptCallReceived(789); EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value()); + EXPECT_FALSE(mThrottleVsyncCallRecorder.waitForUnexpectedCall().has_value()); // The fourth event will be seen by the interceptor and the connection. mCallback->onVSyncEvent(101112, 7847, 86); @@ -408,19 +443,19 @@ TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) { } TEST_F(EventThreadTest, tracksEventConnections) { - EXPECT_EQ(1, mThread->getEventThreadConnectionCount()); + EXPECT_EQ(2, mThread->getEventThreadConnectionCount()); ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY}; sp errorConnection = createConnection(errorConnectionEventRecorder, ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(1, errorConnection); - EXPECT_EQ(2, mThread->getEventThreadConnectionCount()); + EXPECT_EQ(3, mThread->getEventThreadConnectionCount()); ConnectionEventRecorder secondConnectionEventRecorder{0}; sp secondConnection = createConnection(secondConnectionEventRecorder, ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(1, secondConnection); - EXPECT_EQ(3, mThread->getEventThreadConnectionCount()); + EXPECT_EQ(4, mThread->getEventThreadConnectionCount()); // EventThread should enable vsync callbacks. expectVSyncSetEnabledCallReceived(true); @@ -432,7 +467,7 @@ TEST_F(EventThreadTest, tracksEventConnections) { expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u); expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123, 1u); - EXPECT_EQ(2, mThread->getEventThreadConnectionCount()); + EXPECT_EQ(3, mThread->getEventThreadConnectionCount()); } TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) { @@ -514,5 +549,35 @@ TEST_F(EventThreadTest, suppressConfigChanged) { ASSERT_FALSE(args.has_value()); } +TEST_F(EventThreadTest, requestNextVsyncWithThrottleVsyncDoesntPostVSync) { + // Signal that we want the next vsync event to be posted to the throttled connection + mThread->requestNextVsync(mThrottledConnection); + + // EventThread should immediately request a resync. + EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value()); + + // EventThread should enable vsync callbacks. + expectVSyncSetEnabledCallReceived(true); + + // Use the received callback to signal a first vsync event. + // The interceptor should receive the event, but not the connection. + mCallback->onVSyncEvent(123, 456, 789); + expectInterceptCallReceived(123); + expectThrottleVsyncReceived(456, mThrottledConnectionUid); + mThrottledConnectionEventCallRecorder.waitForUnexpectedCall(); + + // Use the received callback to signal a second vsync event. + // The interceptor should receive the event, but the connection should + // not as it was only interested in the first. + mCallback->onVSyncEvent(456, 123, 0); + expectInterceptCallReceived(456); + expectThrottleVsyncReceived(123, mThrottledConnectionUid); + EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value()); + + // EventThread should not change the vsync state as it didn't send the event + // yet + EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value()); +} + } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 1f6f166b45..4762fd4b66 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -1471,6 +1471,34 @@ TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) { EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction()); } +TEST_F(RefreshRateConfigsTest, RefreshRateDividerForUnknownUid) { + auto refreshRateConfigs = + std::make_unique(m30_60_72_90_120Device, + /*currentConfigId=*/HWC_CONFIG_ID_30); + EXPECT_EQ(1, refreshRateConfigs->getRefreshRateDividerForUid(1234)); +} + +TEST_F(RefreshRateConfigsTest, RefreshRateDividerForUid) { + auto refreshRateConfigs = + std::make_unique(m30_60_72_90_120Device, + /*currentConfigId=*/HWC_CONFIG_ID_30); + const uid_t uid = 1234; + refreshRateConfigs->setPreferredRefreshRateForUid(uid, 30); + EXPECT_EQ(1, refreshRateConfigs->getRefreshRateDividerForUid(uid)); + + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_60); + EXPECT_EQ(2, refreshRateConfigs->getRefreshRateDividerForUid(uid)); + + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_72); + EXPECT_EQ(1, refreshRateConfigs->getRefreshRateDividerForUid(uid)); + + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); + EXPECT_EQ(3, refreshRateConfigs->getRefreshRateDividerForUid(uid)); + + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_120); + EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDividerForUid(uid)); +} + } // namespace } // namespace scheduler } // namespace android diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp index 2c8178e684..8cd8372626 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp @@ -131,12 +131,14 @@ void RefreshRateSelectionTest::setupScheduler() { EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(eventThread.get(), ResyncCallback(), + .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, + ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), ResyncCallback(), + .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, + ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); auto vsyncController = std::make_unique(); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index eee940038d..509858a4ab 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -42,7 +42,7 @@ protected: class MockEventThreadConnection : public android::EventThreadConnection { public: explicit MockEventThreadConnection(EventThread* eventThread) - : EventThreadConnection(eventThread, ResyncCallback(), + : EventThreadConnection(eventThread, /*callingUid=*/0, ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress) {} ~MockEventThreadConnection() = default; diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index efee826402..e25d501fe3 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -171,12 +171,14 @@ void SetFrameRateTest::setupScheduler() { EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(eventThread.get(), ResyncCallback(), + .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0, + ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), ResyncCallback(), + .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, + ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); auto vsyncController = std::make_unique(); diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 760bf65fee..68cf330b9c 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -66,13 +66,15 @@ public: EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) .WillOnce(Return( - new EventThreadConnection(eventThread.get(), ResyncCallback(), + new EventThreadConnection(eventThread.get(), /*callingUid=*/0, + ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) .WillOnce(Return( - new EventThreadConnection(sfEventThread.get(), ResyncCallback(), + new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0, + ResyncCallback(), ISurfaceComposer::eConfigChangedSuppress))); EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp index 1e5139c49e..0af5f30649 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp @@ -52,6 +52,7 @@ public: void setPeriod(nsecs_t) final {} void resetModel() final {} bool needsMoreSamples() const final { return false; } + bool isVSyncInPhase(nsecs_t, int) const final { return false; } void dump(std::string&) const final {} private: @@ -88,6 +89,7 @@ public: void setPeriod(nsecs_t) final {} void resetModel() final {} bool needsMoreSamples() const final { return false; } + bool isVSyncInPhase(nsecs_t, int) const final { return false; } void dump(std::string&) const final {} private: diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index 69731fdbed..72b5396047 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -48,6 +48,7 @@ public: MOCK_METHOD1(setPeriod, void(nsecs_t)); MOCK_METHOD0(resetModel, void()); MOCK_CONST_METHOD0(needsMoreSamples, bool()); + MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, int)); MOCK_CONST_METHOD1(dump, void(std::string&)); nsecs_t nextVSyncTime(nsecs_t timePoint) const { diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp index d4cd11dbe1..3d60479111 100644 --- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp @@ -59,16 +59,16 @@ struct VSyncPredictorTest : testing::Test { }; TEST_F(VSyncPredictorTest, reportsAnticipatedPeriod) { - auto [slope, intercept] = tracker.getVSyncPredictionModel(); + auto model = tracker.getVSyncPredictionModel(); - EXPECT_THAT(slope, Eq(mPeriod)); - EXPECT_THAT(intercept, Eq(0)); + EXPECT_THAT(model.slope, Eq(mPeriod)); + EXPECT_THAT(model.intercept, Eq(0)); auto const changedPeriod = 2000; tracker.setPeriod(changedPeriod); - std::tie(slope, intercept) = tracker.getVSyncPredictionModel(); - EXPECT_THAT(slope, Eq(changedPeriod)); - EXPECT_THAT(intercept, Eq(0)); + model = tracker.getVSyncPredictionModel(); + EXPECT_THAT(model.slope, Eq(changedPeriod)); + EXPECT_THAT(model.intercept, Eq(0)); } TEST_F(VSyncPredictorTest, reportsSamplesNeededWhenHasNoDataPoints) { @@ -264,17 +264,17 @@ TEST_F(VSyncPredictorTest, handlesVsyncChange) { } auto const mMaxRoundingError = 100; - auto [slope, intercept] = tracker.getVSyncPredictionModel(); - EXPECT_THAT(slope, IsCloseTo(fastPeriod, mMaxRoundingError)); - EXPECT_THAT(intercept, IsCloseTo(0, mMaxRoundingError)); + auto model = tracker.getVSyncPredictionModel(); + EXPECT_THAT(model.slope, IsCloseTo(fastPeriod, mMaxRoundingError)); + EXPECT_THAT(model.intercept, IsCloseTo(0, mMaxRoundingError)); tracker.setPeriod(slowPeriod); for (auto const& timestamp : simulatedVsyncsSlow) { tracker.addVsyncTimestamp(timestamp); } - std::tie(slope, intercept) = tracker.getVSyncPredictionModel(); - EXPECT_THAT(slope, IsCloseTo(slowPeriod, mMaxRoundingError)); - EXPECT_THAT(intercept, IsCloseTo(0, mMaxRoundingError)); + model = tracker.getVSyncPredictionModel(); + EXPECT_THAT(model.slope, IsCloseTo(slowPeriod, mMaxRoundingError)); + EXPECT_THAT(model.intercept, IsCloseTo(0, mMaxRoundingError)); } TEST_F(VSyncPredictorTest, willBeAccurateUsingPriorResultsForRate) { @@ -296,9 +296,9 @@ TEST_F(VSyncPredictorTest, willBeAccurateUsingPriorResultsForRate) { for (auto const& timestamp : simulatedVsyncsFast) { tracker.addVsyncTimestamp(timestamp); } - auto [slope, intercept] = tracker.getVSyncPredictionModel(); - EXPECT_THAT(slope, Eq(fastPeriod)); - EXPECT_THAT(intercept, Eq(0)); + auto model = tracker.getVSyncPredictionModel(); + EXPECT_THAT(model.slope, Eq(fastPeriod)); + EXPECT_THAT(model.intercept, Eq(0)); tracker.setPeriod(slowPeriod); for (auto const& timestamp : simulatedVsyncsSlow) { @@ -308,16 +308,16 @@ TEST_F(VSyncPredictorTest, willBeAccurateUsingPriorResultsForRate) { // we had a model for 100ns mPeriod before, use that until the new samples are // sufficiently built up tracker.setPeriod(idealPeriod); - std::tie(slope, intercept) = tracker.getVSyncPredictionModel(); - EXPECT_THAT(slope, Eq(fastPeriod)); - EXPECT_THAT(intercept, Eq(0)); + model = tracker.getVSyncPredictionModel(); + EXPECT_THAT(model.slope, Eq(fastPeriod)); + EXPECT_THAT(model.intercept, Eq(0)); for (auto const& timestamp : simulatedVsyncsFast2) { tracker.addVsyncTimestamp(timestamp); } - std::tie(slope, intercept) = tracker.getVSyncPredictionModel(); - EXPECT_THAT(slope, Eq(fastPeriod2)); - EXPECT_THAT(intercept, Eq(0)); + model = tracker.getVSyncPredictionModel(); + EXPECT_THAT(model.slope, Eq(fastPeriod2)); + EXPECT_THAT(model.intercept, Eq(0)); } TEST_F(VSyncPredictorTest, idealModelPredictionsBeforeRegressionModelIsBuilt) { @@ -407,11 +407,9 @@ TEST_F(VSyncPredictorTest, resetsWhenInstructed) { tracker.addVsyncTimestamp(i * realPeriod); } - EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()), - IsCloseTo(realPeriod, mMaxRoundingError)); + EXPECT_THAT(tracker.getVSyncPredictionModel().slope, IsCloseTo(realPeriod, mMaxRoundingError)); tracker.resetModel(); - EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()), - IsCloseTo(idealPeriod, mMaxRoundingError)); + EXPECT_THAT(tracker.getVSyncPredictionModel().slope, IsCloseTo(idealPeriod, mMaxRoundingError)); } TEST_F(VSyncPredictorTest, slopeAlwaysValid) { @@ -450,6 +448,33 @@ TEST_F(VSyncPredictorTest, aPhoneThatHasBeenAroundAWhileCanStillComputePeriod) { EXPECT_THAT(intercept, Eq(0)); } +TEST_F(VSyncPredictorTest, isVSyncInPhase) { + auto last = mNow; + auto const bias = 10; + for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) { + EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod)); + mNow += mPeriod - bias; + last = mNow; + tracker.addVsyncTimestamp(mNow); + mNow += bias; + } + + EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod - bias)); + EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod - bias)); + EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 990), Eq(mNow + 2 * mPeriod - bias)); + + const auto maxDivider = 5; + const auto maxPeriods = 15; + for (int divider = 1; divider < maxDivider; divider++) { + for (int i = 0; i < maxPeriods; i++) { + const bool expectedInPhase = (i % divider) == 0; + EXPECT_THAT(expectedInPhase, tracker.isVSyncInPhase(mNow + i * mPeriod - bias, divider)) + << "vsync at " << mNow + (i + 1) * mPeriod - bias << " is " + << (expectedInPhase ? "not " : "") << "in phase for divider " << divider; + } + } +} + } // 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 0dcaf26bae..a7568e4293 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -42,6 +42,7 @@ public: MOCK_METHOD1(setPeriod, void(nsecs_t)); MOCK_METHOD0(resetModel, void()); MOCK_CONST_METHOD0(needsMoreSamples, bool()); + MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, int)); MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h index 03ddc8508f..de98025fd8 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h +++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h @@ -33,6 +33,7 @@ public: MOCK_METHOD1(setPeriod, void(nsecs_t)); MOCK_METHOD0(resetModel, void()); MOCK_CONST_METHOD0(needsMoreSamples, bool()); + MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, int)); MOCK_CONST_METHOD1(dump, void(std::string&)); }; -- cgit v1.2.3-59-g8ed1b From ce4adf1b97be29a65f5b36c345f36651bff1e619 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 15 Dec 2020 18:45:12 -0800 Subject: SurfaceFlinger: fix early latching of buffers Use the FrameTimeline::SurfaceFrame predicted present time to avoid latching a buffer too early (i.e. before the time SurfaceFlinger planned to latch this buffer when the app requested a vsync callback). Bug: 169901895 Test: expand notification shade and observe systrace Change-Id: I823546992c89f88c0c29b839ce21c79ff1ffcfbd --- services/surfaceflinger/BufferLayer.cpp | 20 ++++++++++++++++++++ services/surfaceflinger/BufferLayer.h | 12 ++++++++++++ services/surfaceflinger/BufferQueueLayer.cpp | 15 +++++++++++++++ services/surfaceflinger/BufferQueueLayer.h | 2 ++ services/surfaceflinger/BufferStateLayer.cpp | 8 ++++++++ services/surfaceflinger/BufferStateLayer.h | 2 ++ 6 files changed, 59 insertions(+) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index fa75ffa403..6561707bcc 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -389,6 +389,20 @@ void BufferLayer::gatherBufferInfo() { mBufferInfo.mFrameLatencyNeeded = true; } +bool BufferLayer::frameIsEarly(nsecs_t expectedPresentTime) const { + // TODO(b/169901895): kEarlyLatchVsyncThreshold should be based on the + // vsync period. We can do this change as soon as ag/13100772 is merged. + constexpr static std::chrono::nanoseconds kEarlyLatchVsyncThreshold = 5ms; + + const auto presentTime = nextPredictedPresentTime(); + if (std::abs(presentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold.count()) { + return false; + } + + return presentTime >= expectedPresentTime && + presentTime - expectedPresentTime >= kEarlyLatchVsyncThreshold.count(); +} + bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) { ATRACE_CALL(); @@ -421,6 +435,12 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, return false; } + if (frameIsEarly(expectedPresentTime)) { + ATRACE_NAME("frameIsEarly()"); + mFlinger->signalLayerUpdate(); + return false; + } + // If the head buffer's acquire fence hasn't signaled yet, return and // try again later if (!fenceHasSignaled()) { diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 63dfe5f5d9..5cd9a7cde1 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -224,6 +224,18 @@ private: std::unique_ptr mCompositionState; FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; + + // Returns true if the next frame is considered too early to present + // at the given expectedPresentTime + bool frameIsEarly(nsecs_t expectedPresentTime) const; + + // Returns the predicted present time of the next frame if available or + // 0 otherwise. + virtual nsecs_t nextPredictedPresentTime() const = 0; + + // The amount of time SF can delay a frame if it is considered early based + // on the VsyncModulator::VsyncConfig::appWorkDuration + static constexpr std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms; }; } // namespace android diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 56d874258e..e8e31db236 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -222,6 +222,21 @@ bool BufferQueueLayer::hasFrameUpdate() const { return mQueuedFrames > 0; } +nsecs_t BufferQueueLayer::nextPredictedPresentTime() const { + Mutex::Autolock lock(mQueueItemLock); + if (mQueueItems.empty()) { + return 0; + } + + const auto& bufferData = mQueueItems[0]; + + if (!bufferData.item.mIsAutoTimestamp || !bufferData.surfaceFrame) { + return 0; + } + + return bufferData.surfaceFrame->getPredictions().presentTime; +} + status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) { // This boolean is used to make sure that SurfaceFlinger's shadow copy diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 3551026f17..2347d8cec7 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -116,6 +116,8 @@ private: // Temporary - Used only for LEGACY camera mode. uint32_t getProducerStickyTransform() const; + nsecs_t nextPredictedPresentTime() const override; + sp mConsumer; sp mProducer; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index df1472d0d4..7ec7f36548 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -601,6 +601,14 @@ bool BufferStateLayer::hasFrameUpdate() const { return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr); } +nsecs_t BufferStateLayer::nextPredictedPresentTime() const { + if (!getDrawingState().isAutoTimestamp || !mSurfaceFrame) { + return 0; + } + + return mSurfaceFrame->getPredictions().presentTime; +} + status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime, nsecs_t /*expectedPresentTime*/) { const State& s(getDrawingState()); diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 734f647b01..6414e6be60 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -152,6 +152,8 @@ private: bool bufferNeedsFiltering() const override; + nsecs_t nextPredictedPresentTime() const override; + static const std::array IDENTITY_MATRIX; std::unique_ptr mTextureImage; -- cgit v1.2.3-59-g8ed1b From 63a3e592e71169909b06843f781f7ea2cd1ff958 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 6 Jan 2021 10:47:15 -0800 Subject: SurfaceFlinger: Layer::shouldPresentNow should consider early frames Move the decision whether to latch a buffer or not based on the expected present time (that is whether a frame is considered too early or out of vsync phase) from Layer::latchBuffer to Layer::shouldPresentNow as the code assumes that Layer::latchBuffer would not fail based on the expected present. Bug: 176755514 Bug: 176416352 Test: atest CtsViewTestCases:android.view.cts.ASurfaceControlTest Test: atest FrameRateOverrideHostTest Change-Id: Ib83bda41c824549011f12fa5414263c8b03032e4 --- services/surfaceflinger/BufferLayer.cpp | 55 +++++++++++++++++++--------- services/surfaceflinger/BufferLayer.h | 23 ++++++++---- services/surfaceflinger/BufferQueueLayer.cpp | 16 ++------ services/surfaceflinger/BufferQueueLayer.h | 5 ++- services/surfaceflinger/BufferStateLayer.cpp | 12 +----- services/surfaceflinger/BufferStateLayer.h | 4 +- 6 files changed, 63 insertions(+), 52 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 6561707bcc..424a8b350a 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -389,33 +389,58 @@ void BufferLayer::gatherBufferInfo() { mBufferInfo.mFrameLatencyNeeded = true; } +bool BufferLayer::shouldPresentNow(nsecs_t expectedPresentTime) const { + // If this is not a valid vsync for the layer's uid, return and try again later + const bool isVsyncValidForUid = + mFlinger->mScheduler->isVsyncValid(expectedPresentTime, mOwnerUid); + if (!isVsyncValidForUid) { + ATRACE_NAME("!isVsyncValidForUid"); + return false; + } + + // AutoRefresh layers and sideband streams should always be presented + if (getSidebandStreamChanged() || getAutoRefresh()) { + return true; + } + + // If the next planned present time is not current, return and try again later + if (frameIsEarly(expectedPresentTime)) { + ATRACE_NAME("frameIsEarly()"); + return false; + } + + // If this layer doesn't have a frame is shouldn't be presented + if (!hasFrameUpdate()) { + return false; + } + + // Defer to the derived class to decide whether the next buffer is due for + // presentation. + return isBufferDue(expectedPresentTime); +} + bool BufferLayer::frameIsEarly(nsecs_t expectedPresentTime) const { // TODO(b/169901895): kEarlyLatchVsyncThreshold should be based on the // vsync period. We can do this change as soon as ag/13100772 is merged. constexpr static std::chrono::nanoseconds kEarlyLatchVsyncThreshold = 5ms; const auto presentTime = nextPredictedPresentTime(); - if (std::abs(presentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold.count()) { + if (!presentTime.has_value()) { return false; } - return presentTime >= expectedPresentTime && - presentTime - expectedPresentTime >= kEarlyLatchVsyncThreshold.count(); + if (std::abs(*presentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold.count()) { + return false; + } + + return *presentTime >= expectedPresentTime && + *presentTime - expectedPresentTime >= kEarlyLatchVsyncThreshold.count(); } bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) { ATRACE_CALL(); - // If this is not a valid vsync for the layer's uid, return and try again later - const bool isVsyncValidForUid = - mFlinger->mScheduler->isVsyncValid(expectedPresentTime, mOwnerUid); - if (!isVsyncValidForUid) { - ATRACE_NAME("!isVsyncValidForUid"); - mFlinger->setTransactionFlags(eTraversalNeeded); - return false; - } - bool refreshRequired = latchSidebandStream(recomputeVisibleRegions); if (refreshRequired) { @@ -435,12 +460,6 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, return false; } - if (frameIsEarly(expectedPresentTime)) { - ATRACE_NAME("frameIsEarly()"); - mFlinger->signalLayerUpdate(); - return false; - } - // If the head buffer's acquire fence hasn't signaled yet, return and // try again later if (!fenceHasSignaled()) { diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 5cd9a7cde1..2118f4ad18 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -175,12 +175,24 @@ protected: void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override; // Transform hint provided to the producer. This must be accessed holding - /// the mStateLock. + // the mStateLock. ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0; bool getAutoRefresh() const { return mAutoRefresh; } bool getSidebandStreamChanged() const { return mSidebandStreamChanged; } + // Returns true if the next buffer should be presented at the expected present time + bool shouldPresentNow(nsecs_t expectedPresentTime) const final; + + // Returns true if the next buffer should be presented at the expected present time, + // overridden by BufferStateLayer and BufferQueueLayer for implementation + // specific logic + virtual bool isBufferDue(nsecs_t /*expectedPresentTime*/) const = 0; + + // Returns true if the next frame is considered too early to present + // at the given expectedPresentTime + bool frameIsEarly(nsecs_t expectedPresentTime) const; + std::atomic mAutoRefresh{false}; std::atomic mSidebandStreamChanged{false}; @@ -225,13 +237,8 @@ private: FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; - // Returns true if the next frame is considered too early to present - // at the given expectedPresentTime - bool frameIsEarly(nsecs_t expectedPresentTime) const; - - // Returns the predicted present time of the next frame if available or - // 0 otherwise. - virtual nsecs_t nextPredictedPresentTime() const = 0; + // Returns the predicted present time of the next frame if available + virtual std::optional nextPredictedPresentTime() const = 0; // The amount of time SF can delay a frame if it is considered early based // on the VsyncModulator::VsyncConfig::appWorkDuration diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 04cec4fafe..32e6b1098f 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -100,15 +100,7 @@ int32_t BufferQueueLayer::getQueuedFrameCount() const { return mQueuedFrames; } -bool BufferQueueLayer::shouldPresentNow(nsecs_t expectedPresentTime) const { - if (getSidebandStreamChanged() || getAutoRefresh()) { - return true; - } - - if (!hasFrameUpdate()) { - return false; - } - +bool BufferQueueLayer::isBufferDue(nsecs_t expectedPresentTime) const { Mutex::Autolock lock(mQueueItemLock); const int64_t addedTime = mQueueItems[0].item.mTimestamp; @@ -223,16 +215,16 @@ bool BufferQueueLayer::hasFrameUpdate() const { return mQueuedFrames > 0; } -nsecs_t BufferQueueLayer::nextPredictedPresentTime() const { +std::optional BufferQueueLayer::nextPredictedPresentTime() const { Mutex::Autolock lock(mQueueItemLock); if (mQueueItems.empty()) { - return 0; + return std::nullopt; } const auto& bufferData = mQueueItems[0]; if (!bufferData.item.mIsAutoTimestamp || !bufferData.surfaceFrame) { - return 0; + return std::nullopt; } return bufferData.surfaceFrame->getPredictions().presentTime; diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 2347d8cec7..0e8fdbe092 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -53,7 +53,8 @@ public: int32_t getQueuedFrameCount() const override; - bool shouldPresentNow(nsecs_t expectedPresentTime) const override; + // Returns true if the next buffer should be presented at the expected present time + bool isBufferDue(nsecs_t expectedPresentTime) const override; // Implements BufferLayer. bool fenceHasSignaled() const override; @@ -116,7 +117,7 @@ private: // Temporary - Used only for LEGACY camera mode. uint32_t getProducerStickyTransform() const; - nsecs_t nextPredictedPresentTime() const override; + std::optional nextPredictedPresentTime() const override; sp mConsumer; sp mProducer; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index bca1c69c0f..ad08f82b94 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -212,14 +212,6 @@ void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr BufferStateLayer::nextPredictedPresentTime() const { if (!getDrawingState().isAutoTimestamp || !mSurfaceFrame) { - return 0; + return std::nullopt; } return mSurfaceFrame->getPredictions().presentTime; diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 6414e6be60..bc508e3427 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -45,7 +45,7 @@ public: void finalizeFrameEventHistory(const std::shared_ptr& glDoneFence, const CompositorTiming& compositorTiming) override; - bool shouldPresentNow(nsecs_t expectedPresentTime) const override; + bool isBufferDue(nsecs_t /*expectedPresentTime*/) const override { return true; } uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override { return flags; @@ -152,7 +152,7 @@ private: bool bufferNeedsFiltering() const override; - nsecs_t nextPredictedPresentTime() const override; + std::optional nextPredictedPresentTime() const override; static const std::array IDENTITY_MATRIX; -- cgit v1.2.3-59-g8ed1b From 045b70051322dcce2f9519b6113f349ef50d41fa Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Thu, 7 Jan 2021 16:56:24 +0100 Subject: SF: Don't cache display modes in HWComposer The display modes should be stored only in DisplayDevice. Having the state also in HWComposer is unnesesary and hard to keep in sync with SF, e.g. during hotplug processing of displays which can change their supported modes. Any HWC calls which need to validate their parameters need to go through display device. This additinally makes the code more undestandable. Bug: 159590486 Test: presubmit Change-Id: I40b03c09a5fd6092fca0682d602deb70db022fa5 --- services/surfaceflinger/BufferLayer.cpp | 2 +- .../include/compositionengine/DisplaySurface.h | 3 +- .../compositionengine/mock/DisplaySurface.h | 3 +- .../CompositionEngine/src/RenderSurface.cpp | 3 +- .../CompositionEngine/tests/MockHWComposer.h | 7 +- .../CompositionEngine/tests/RenderSurfaceTest.cpp | 5 +- services/surfaceflinger/DisplayDevice.cpp | 25 +++ services/surfaceflinger/DisplayDevice.h | 6 + .../surfaceflinger/DisplayHardware/DisplayMode.h | 2 + .../DisplayHardware/FramebufferSurface.cpp | 38 ++-- .../DisplayHardware/FramebufferSurface.h | 14 +- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 113 ++++-------- .../surfaceflinger/DisplayHardware/HWComposer.h | 33 ++-- .../DisplayHardware/VirtualDisplaySurface.cpp | 10 +- .../DisplayHardware/VirtualDisplaySurface.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 73 +++++--- services/surfaceflinger/SurfaceFlinger.h | 1 + .../tests/fakehwc/SFFakeHwc_test.cpp | 201 ++++++++++++++++++--- .../tests/unittests/CompositionTest.cpp | 18 +- .../tests/unittests/HWComposerTest.cpp | 85 --------- .../tests/unittests/RefreshRateSelectionTest.cpp | 2 +- .../tests/unittests/SetFrameRateTest.cpp | 2 +- .../SurfaceFlinger_HandleTransactionLockedTest.cpp | 6 +- .../tests/unittests/TestableSurfaceFlinger.h | 89 +++++++-- .../tests/unittests/TransactionApplicationTest.cpp | 2 +- 25 files changed, 436 insertions(+), 309 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 39ae2fdb42..ec81ff7b14 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -377,7 +377,7 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, displayId && mFlinger->getHwComposer().isConnected(*displayId)) { // The HWC doesn't support present fences, so use the refresh // timestamp instead. - const nsecs_t actualPresentTime = mFlinger->getHwComposer().getRefreshTimestamp(*displayId); + const nsecs_t actualPresentTime = display->getRefreshTimestamp(); mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime); mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, actualPresentTime, diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h index 6559ed89d7..4502eee97c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -71,7 +72,7 @@ public: virtual void dumpAsString(String8& result) const = 0; - virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0; + virtual void resizeBuffers(const ui::Size&) = 0; virtual const sp& getClientTargetAcquireFence() const = 0; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h index 31b5f95c62..168e433da2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h @@ -18,6 +18,7 @@ #include #include +#include #include namespace android::compositionengine::mock { @@ -32,7 +33,7 @@ public: MOCK_METHOD0(advanceFrame, status_t()); MOCK_METHOD0(onFrameCommitted, void()); MOCK_CONST_METHOD1(dumpAsString, void(String8& result)); - MOCK_METHOD2(resizeBuffers, void(uint32_t, uint32_t)); + MOCK_METHOD1(resizeBuffers, void(const ui::Size&)); MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp&()); }; diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index b47f7fd8a9..3bef77dde1 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -96,8 +96,7 @@ const sp& RenderSurface::getClientTargetAcquireFence() const { } void RenderSurface::setDisplaySize(const ui::Size& size) { - mDisplaySurface->resizeBuffers(static_cast(size.width), - static_cast(size.height)); + mDisplaySurface->resizeBuffers(size); mSize = size; } diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index 3133e9005d..ab003852de 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -85,16 +85,15 @@ public: MOCK_CONST_METHOD0(updatesDeviceProductInfoOnHotplugReconnect, bool()); MOCK_METHOD2(onVsync, bool(hal::HWDisplayId, int64_t)); MOCK_METHOD2(setVsyncEnabled, void(PhysicalDisplayId, hal::Vsync)); - MOCK_CONST_METHOD1(getRefreshTimestamp, nsecs_t(PhysicalDisplayId)); MOCK_CONST_METHOD1(isConnected, bool(PhysicalDisplayId)); - MOCK_CONST_METHOD1(getModes, DisplayModes(PhysicalDisplayId)); - MOCK_CONST_METHOD1(getActiveMode, DisplayModePtr(PhysicalDisplayId)); + MOCK_CONST_METHOD1(getModes, std::vector(PhysicalDisplayId)); + MOCK_CONST_METHOD1(getActiveMode, std::optional(PhysicalDisplayId)); MOCK_CONST_METHOD1(getColorModes, std::vector(PhysicalDisplayId)); MOCK_METHOD3(setActiveColorMode, status_t(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent)); MOCK_CONST_METHOD0(isUsingVrComposer, bool()); MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(PhysicalDisplayId)); MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(PhysicalDisplayId)); - MOCK_CONST_METHOD1(getDisplayVsyncPeriod, nsecs_t(PhysicalDisplayId)); + MOCK_CONST_METHOD2(getDisplayVsyncPeriod, status_t(PhysicalDisplayId, nsecs_t*)); MOCK_METHOD4(setActiveModeWithConstraints, status_t(PhysicalDisplayId, hal::HWConfigId, const hal::VsyncPeriodChangeConstraints&, diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index cd39733839..5ef5d7b5cb 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -119,9 +119,10 @@ TEST_F(RenderSurfaceTest, getClientTargetAcquireFenceForwardsCall) { */ TEST_F(RenderSurfaceTest, setDisplaySizeAppliesChange) { - EXPECT_CALL(*mDisplaySurface, resizeBuffers(640, 480)).Times(1); + const ui::Size size(640, 480); + EXPECT_CALL(*mDisplaySurface, resizeBuffers(size)).Times(1); - mSurface.setDisplaySize(ui::Size(640, 480)); + mSurface.setDisplaySize(size); } /* diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index b4a3ed1327..a785968515 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -179,6 +179,31 @@ DisplayModePtr DisplayDevice::getMode(DisplayModeId modeId) const { return nullptr; } +nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const { + const auto physicalId = getPhysicalId(); + if (!mHwComposer.isConnected(physicalId)) { + return 0; + } + + nsecs_t vsyncPeriod; + const auto status = mHwComposer.getDisplayVsyncPeriod(physicalId, &vsyncPeriod); + if (status == NO_ERROR) { + return vsyncPeriod; + } + + return getActiveMode()->getFps().getPeriodNsecs(); +} + +nsecs_t DisplayDevice::getRefreshTimestamp() const { + const nsecs_t now = systemTime(CLOCK_MONOTONIC); + const auto vsyncPeriodNanos = getVsyncPeriodFromHWC(); + return now - ((now - mLastHwVsync) % vsyncPeriodNanos); +} + +void DisplayDevice::onVsync(nsecs_t timestamp) { + mLastHwVsync = timestamp; +} + ui::Dataspace DisplayDevice::getCompositionDataSpace() const { return mCompositionDisplay->getState().dataspace; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 6f07964ed1..b4db933e19 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -176,6 +176,10 @@ public: // set-top boxes after a hotplug reconnect. DisplayModePtr getMode(DisplayModeId) const; + void onVsync(nsecs_t timestamp); + nsecs_t getVsyncPeriodFromHWC() const; + nsecs_t getRefreshTimestamp() const; + // release HWC resources (if any) for removable displays void disconnect(); @@ -207,6 +211,8 @@ private: DisplayModeId mActiveModeId; const DisplayModes mSupportedModes; + std::atomic mLastHwVsync = 0; + // TODO(b/74619554): Remove special cases for primary display. const bool mIsPrimary; diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h index 61c1b61c91..31d1245ed0 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayMode.h +++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -113,6 +114,7 @@ public: int32_t getWidth() const { return mWidth; } int32_t getHeight() const { return mHeight; } + ui::Size getSize() const { return {mWidth, mHeight}; } Fps getFps() const { return mFps; } nsecs_t getVsyncPeriod() const { return mFps.getPeriodNsecs(); } float getDpiX() const { return mDpiX; } diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 3e856bbbb1..f7fc162884 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -58,11 +58,10 @@ using ui::Dataspace; FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId, const sp& consumer, - uint32_t maxWidth, uint32_t maxHeight) + const ui::Size& size, const ui::Size& maxSize) : ConsumerBase(consumer), mDisplayId(displayId), - mMaxWidth(maxWidth), - mMaxHeight(maxHeight), + mMaxSize(maxSize), mCurrentBufferSlot(-1), mCurrentBuffer(), mCurrentFence(Fence::NO_FENCE), @@ -77,15 +76,14 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displa mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER); - const auto& activeMode = mHwc.getActiveMode(displayId); - ui::Size limitedSize = limitFramebufferSize(activeMode->getWidth(), activeMode->getHeight()); + const auto limitedSize = limitFramebufferSize(size); mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height); mConsumer->setMaxAcquiredBufferCount( SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1); } -void FramebufferSurface::resizeBuffers(uint32_t width, uint32_t height) { - ui::Size limitedSize = limitFramebufferSize(width, height); +void FramebufferSurface::resizeBuffers(const ui::Size& newSize) { + const auto limitedSize = limitFramebufferSize(newSize); mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height); } @@ -181,24 +179,24 @@ void FramebufferSurface::onFrameCommitted() { } } -ui::Size FramebufferSurface::limitFramebufferSize(uint32_t width, uint32_t height) { - ui::Size framebufferSize(width, height); - bool wasLimited = true; - if (width > mMaxWidth && mMaxWidth != 0) { - float aspectRatio = float(width) / float(height); - framebufferSize.height = mMaxWidth / aspectRatio; - framebufferSize.width = mMaxWidth; +ui::Size FramebufferSurface::limitFramebufferSize(const ui::Size& size) { + ui::Size limitedSize = size; + bool wasLimited = false; + if (size.width > mMaxSize.width && mMaxSize.width != 0) { + const float aspectRatio = static_cast(size.width) / size.height; + limitedSize.height = mMaxSize.width / aspectRatio; + limitedSize.width = mMaxSize.width; wasLimited = true; } - if (height > mMaxHeight && mMaxHeight != 0) { - float aspectRatio = float(width) / float(height); - framebufferSize.height = mMaxHeight; - framebufferSize.width = mMaxHeight * aspectRatio; + if (size.height > mMaxSize.height && mMaxSize.height != 0) { + const float aspectRatio = static_cast(size.width) / size.height; + limitedSize.height = mMaxSize.height; + limitedSize.width = mMaxSize.height * aspectRatio; wasLimited = true; } ALOGI_IF(wasLimited, "framebuffer size has been limited to [%dx%d] from [%dx%d]", - framebufferSize.width, framebufferSize.height, width, height); - return framebufferSize; + limitedSize.width, limitedSize.height, size.width, size.height); + return limitedSize; } void FramebufferSurface::dumpAsString(String8& result) const { diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index 759943afa3..5d1e131d69 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -41,8 +41,8 @@ class HWComposer; class FramebufferSurface : public ConsumerBase, public compositionengine::DisplaySurface { public: FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId, - const sp& consumer, uint32_t maxWidth, - uint32_t maxHeight); + const sp& consumer, const ui::Size& size, + const ui::Size& maxSize); virtual status_t beginFrame(bool mustRecompose); virtual status_t prepareFrame(CompositionType compositionType); @@ -50,7 +50,7 @@ public: virtual void onFrameCommitted(); virtual void dumpAsString(String8& result) const; - virtual void resizeBuffers(uint32_t width, uint32_t height); + virtual void resizeBuffers(const ui::Size&) override; virtual const sp& getClientTargetAcquireFence() const override; @@ -62,7 +62,7 @@ private: virtual void dumpLocked(String8& result, const char* prefix) const; // Limits the width and height by the maximum width specified in the constructor. - ui::Size limitFramebufferSize(uint32_t width, uint32_t height); + ui::Size limitFramebufferSize(const ui::Size&); // nextBuffer waits for and then latches the next buffer from the // BufferQueue and releases the previously latched buffer to the @@ -74,11 +74,7 @@ private: // Framebuffer size has a dimension limitation in pixels based on the graphics capabilities of // the device. - const uint32_t mMaxWidth; - - // Framebuffer size has a dimension limitation in pixels based on the graphics capabilities of - // the device. - const uint32_t mMaxHeight; + const ui::Size mMaxSize; // mCurrentBufferIndex is the slot index of the current buffer or // INVALID_BUFFER_SLOT to indicate that either there is no current buffer diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 46dc54e90f..b9a8e4be37 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -223,8 +223,6 @@ bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) { __FUNCTION__, to_string(*displayId).c_str()); { - std::lock_guard lock(displayData.lastHwVsyncLock); - // There have been reports of HWCs that signal several vsync events // with the same timestamp when turning the display off and on. This // is a bug in the HWC implementation, but filter the extra events @@ -295,11 +293,10 @@ void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId, hal::DisplayType::PHYSICAL); newDisplay->setConnected(true); displayData.hwcDisplay = std::move(newDisplay); - loadModes(displayData, hwcDisplayId); } int32_t HWComposer::getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId configId, - hal::Attribute attribute) { + hal::Attribute attribute) const { int32_t value = 0; auto error = static_cast( mComposer->getDisplayAttribute(hwcDisplayId, configId, attribute, &value)); @@ -308,30 +305,6 @@ int32_t HWComposer::getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId return value; } -void HWComposer::loadModes(DisplayData& displayData, hal::HWDisplayId hwcDisplayId) { - ALOGV("[HWC display %" PRIu64 "] %s", hwcDisplayId, __FUNCTION__); - - std::vector configIds; - auto error = static_cast(mComposer->getDisplayConfigs(hwcDisplayId, &configIds)); - RETURN_IF_HWC_ERROR_FOR("getDisplayConfigs", error, *toPhysicalDisplayId(hwcDisplayId)); - - displayData.modes.clear(); - for (auto configId : configIds) { - auto mode = DisplayMode::Builder(configId) - .setId(DisplayModeId(displayData.modes.size())) - .setWidth(getAttribute(hwcDisplayId, configId, hal::Attribute::WIDTH)) - .setHeight(getAttribute(hwcDisplayId, configId, hal::Attribute::HEIGHT)) - .setVsyncPeriod(getAttribute(hwcDisplayId, configId, - hal::Attribute::VSYNC_PERIOD)) - .setDpiX(getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X)) - .setDpiY(getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y)) - .setConfigGroup(getAttribute(hwcDisplayId, configId, - hal::Attribute::CONFIG_GROUP)) - .build(); - displayData.modes.push_back(std::move(mode)); - } -} - HWC2::Layer* HWComposer::createLayer(HalDisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId, nullptr); @@ -348,55 +321,50 @@ void HWComposer::destroyLayer(HalDisplayId displayId, HWC2::Layer* layer) { RETURN_IF_HWC_ERROR(error, displayId); } -nsecs_t HWComposer::getRefreshTimestamp(PhysicalDisplayId displayId) const { - RETURN_IF_INVALID_DISPLAY(displayId, 0); - const auto& displayData = mDisplayData.at(displayId); - // this returns the last refresh timestamp. - // if the last one is not available, we estimate it based on - // the refresh period and whatever closest timestamp we have. - std::lock_guard lock(displayData.lastHwVsyncLock); - nsecs_t now = systemTime(CLOCK_MONOTONIC); - auto vsyncPeriodNanos = getDisplayVsyncPeriod(displayId); - return now - ((now - displayData.lastHwVsync) % vsyncPeriodNanos); -} - bool HWComposer::isConnected(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, false); return mDisplayData.at(displayId).hwcDisplay->isConnected(); } -DisplayModes HWComposer::getModes(PhysicalDisplayId displayId) const { +std::vector HWComposer::getModes(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, {}); - // We cache the modes when the DisplayData is created on hotplug. If the modes need to - // change HWC will send a hotplug event which will recreate displayData. - return mDisplayData.at(displayId).modes; + const auto hwcDisplayId = mDisplayData.at(displayId).hwcDisplay->getId(); + std::vector configIds; + auto error = static_cast(mComposer->getDisplayConfigs(hwcDisplayId, &configIds)); + RETURN_IF_HWC_ERROR_FOR("getDisplayConfigs", error, *toPhysicalDisplayId(hwcDisplayId), {}); + + std::vector modes; + modes.reserve(configIds.size()); + for (auto configId : configIds) { + modes.push_back(HWCDisplayMode{ + .hwcId = configId, + .width = getAttribute(hwcDisplayId, configId, hal::Attribute::WIDTH), + .height = getAttribute(hwcDisplayId, configId, hal::Attribute::HEIGHT), + .vsyncPeriod = getAttribute(hwcDisplayId, configId, hal::Attribute::VSYNC_PERIOD), + .dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X), + .dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y), + .configGroup = getAttribute(hwcDisplayId, configId, hal::Attribute::CONFIG_GROUP), + }); + } + + return modes; } -DisplayModePtr HWComposer::getActiveMode(PhysicalDisplayId displayId) const { - RETURN_IF_INVALID_DISPLAY(displayId, nullptr); +std::optional HWComposer::getActiveMode(PhysicalDisplayId displayId) const { + RETURN_IF_INVALID_DISPLAY(displayId, std::nullopt); const auto hwcId = *fromPhysicalDisplayId(displayId); ALOGV("[%" PRIu64 "] getActiveMode", hwcId); hal::HWConfigId configId; auto error = static_cast(mComposer->getActiveConfig(hwcId, &configId)); - const auto& modes = mDisplayData.at(displayId).modes; if (error == hal::Error::BAD_CONFIG) { LOG_DISPLAY_ERROR(displayId, "No active mode"); - return nullptr; + return std::nullopt; } - RETURN_IF_HWC_ERROR(error, displayId, nullptr); - - const auto it = std::find_if(modes.begin(), modes.end(), - [configId](auto mode) { return mode->getHwcId() == configId; }); - if (it == modes.end()) { - LOG_DISPLAY_ERROR(displayId, "Unknown mode"); - return nullptr; - } - - return *it; + return configId; } // Composer 2.4 @@ -421,27 +389,20 @@ bool HWComposer::isVsyncPeriodSwitchSupported(PhysicalDisplayId displayId) const return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported(); } -nsecs_t HWComposer::getDisplayVsyncPeriod(PhysicalDisplayId displayId) const { +status_t HWComposer::getDisplayVsyncPeriod(PhysicalDisplayId displayId, + nsecs_t* outVsyncPeriod) const { RETURN_IF_INVALID_DISPLAY(displayId, 0); - if (isVsyncPeriodSwitchSupported(displayId)) { - const auto hwcId = *fromPhysicalDisplayId(displayId); - Hwc2::VsyncPeriodNanos vsyncPeriodNanos = 0; - auto error = - static_cast(mComposer->getDisplayVsyncPeriod(hwcId, &vsyncPeriodNanos)); - RETURN_IF_HWC_ERROR(error, displayId, 0); - return static_cast(vsyncPeriodNanos); - } - - // Get the default vsync period - auto mode = getActiveMode(displayId); - - if (!mode) { - // HWC has updated the display modes and hasn't notified us yet. - RETURN_IF_HWC_ERROR(hal::Error::BAD_CONFIG, displayId, 0); + if (!isVsyncPeriodSwitchSupported(displayId)) { + return INVALID_OPERATION; } - - return mode->getVsyncPeriod(); + const auto hwcId = *fromPhysicalDisplayId(displayId); + Hwc2::VsyncPeriodNanos vsyncPeriodNanos = 0; + auto error = + static_cast(mComposer->getDisplayVsyncPeriod(hwcId, &vsyncPeriodNanos)); + RETURN_IF_HWC_ERROR(error, displayId, 0); + *outVsyncPeriod = static_cast(vsyncPeriodNanos); + return NO_ERROR; } std::vector HWComposer::getColorModes(PhysicalDisplayId displayId) const { diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 1ffe276ecd..f9c8e2efef 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -83,6 +83,16 @@ public: ClientTargetProperty clientTargetProperty; }; + struct HWCDisplayMode { + hal::HWConfigId hwcId; + int32_t width = -1; + int32_t height = -1; + nsecs_t vsyncPeriod = -1; + int32_t dpiX = -1; + int32_t dpiY = -1; + int32_t configGroup = -1; + }; + virtual ~HWComposer(); virtual void setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) = 0; @@ -182,12 +192,11 @@ public: virtual bool onVsync(hal::HWDisplayId, int64_t timestamp) = 0; virtual void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) = 0; - virtual nsecs_t getRefreshTimestamp(PhysicalDisplayId) const = 0; virtual bool isConnected(PhysicalDisplayId) const = 0; - virtual DisplayModes getModes(PhysicalDisplayId) const = 0; + virtual std::vector getModes(PhysicalDisplayId) const = 0; - virtual DisplayModePtr getActiveMode(PhysicalDisplayId) const = 0; + virtual std::optional getActiveMode(PhysicalDisplayId) const = 0; virtual std::vector getColorModes(PhysicalDisplayId) const = 0; @@ -197,7 +206,8 @@ public: // Composer 2.4 virtual DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const = 0; virtual bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const = 0; - virtual nsecs_t getDisplayVsyncPeriod(PhysicalDisplayId) const = 0; + virtual status_t getDisplayVsyncPeriod(PhysicalDisplayId displayId, + nsecs_t* outVsyncPeriod) const = 0; virtual status_t setActiveModeWithConstraints(PhysicalDisplayId, hal::HWConfigId, const hal::VsyncPeriodChangeConstraints&, hal::VsyncPeriodChangeTimeline* outTimeline) = 0; @@ -314,12 +324,11 @@ public: bool onVsync(hal::HWDisplayId, int64_t timestamp) override; void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) override; - nsecs_t getRefreshTimestamp(PhysicalDisplayId) const override; bool isConnected(PhysicalDisplayId) const override; - DisplayModes getModes(PhysicalDisplayId) const override; + std::vector getModes(PhysicalDisplayId) const override; - DisplayModePtr getActiveMode(PhysicalDisplayId) const override; + std::optional getActiveMode(PhysicalDisplayId) const override; std::vector getColorModes(PhysicalDisplayId) const override; @@ -328,7 +337,8 @@ public: // Composer 2.4 DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override; bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const override; - nsecs_t getDisplayVsyncPeriod(PhysicalDisplayId displayId) const override; + status_t getDisplayVsyncPeriod(PhysicalDisplayId displayId, + nsecs_t* outVsyncPeriod) const override; status_t setActiveModeWithConstraints(PhysicalDisplayId, hal::HWConfigId, const hal::VsyncPeriodChangeConstraints&, hal::VsyncPeriodChangeTimeline* outTimeline) override; @@ -365,7 +375,6 @@ private: std::unordered_map> releaseFences; buffer_handle_t outbufHandle = nullptr; sp outbufAcquireFence = Fence::NO_FENCE; - DisplayModes modes; bool validateWasSkipped; hal::Error presentError; @@ -375,8 +384,7 @@ private: std::mutex vsyncEnabledLock; hal::Vsync vsyncEnabled GUARDED_BY(vsyncEnabledLock) = hal::Vsync::DISABLE; - mutable std::mutex lastHwVsyncLock; - nsecs_t lastHwVsync GUARDED_BY(lastHwVsyncLock) = 0; + nsecs_t lastHwVsync = 0; }; std::optional onHotplugConnect(hal::HWDisplayId); @@ -384,8 +392,7 @@ private: bool shouldIgnoreHotplugConnect(hal::HWDisplayId, bool hasDisplayIdentificationData) const; int32_t getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId configId, - hal::Attribute attribute); - void loadModes(DisplayData& displayData, hal::HWDisplayId hwcDisplayId); + hal::Attribute attribute) const; void loadCapabilities(); void loadLayerMetadataSupport(); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 2ac67cbe41..e26ab117b8 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -291,11 +291,11 @@ void VirtualDisplaySurface::onFrameCommitted() { void VirtualDisplaySurface::dumpAsString(String8& /* result */) const { } -void VirtualDisplaySurface::resizeBuffers(const uint32_t w, const uint32_t h) { - mQueueBufferOutput.width = w; - mQueueBufferOutput.height = h; - mSinkBufferWidth = w; - mSinkBufferHeight = h; +void VirtualDisplaySurface::resizeBuffers(const ui::Size& newSize) { + mQueueBufferOutput.width = newSize.width; + mQueueBufferOutput.height = newSize.height; + mSinkBufferWidth = newSize.width; + mSinkBufferHeight = newSize.height; } const sp& VirtualDisplaySurface::getClientTargetAcquireFence() const { diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index fba0e3bd8a..bbb6306920 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -90,7 +90,7 @@ public: virtual status_t advanceFrame(); virtual void onFrameCommitted(); virtual void dumpAsString(String8& result) const; - virtual void resizeBuffers(const uint32_t w, const uint32_t h); + virtual void resizeBuffers(const ui::Size&) override; virtual const sp& getClientTargetAcquireFence() const override; private: diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a63a3d704c..6b7862787e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -1586,12 +1587,11 @@ void SurfaceFlinger::signalRefresh() { } nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const { - const auto displayId = getInternalDisplayIdLocked(); - if (!displayId || !getHwComposer().isConnected(*displayId)) { - return 0; + if (const auto display = getDefaultDisplayDeviceLocked()) { + return display->getVsyncPeriodFromHWC(); } - return getHwComposer().getDisplayVsyncPeriod(*displayId); + return 0; } void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId, @@ -1605,6 +1605,12 @@ void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hal::HWDisplayId hwcDis return; } + if (const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId)) { + auto token = getPhysicalDisplayTokenLocked(*displayId); + auto display = getDisplayDeviceLocked(token); + display->onVsync(timestamp); + } + if (!getHwComposer().onVsync(hwcDisplayId, timestamp)) { return; } @@ -2223,8 +2229,7 @@ void SurfaceFlinger::postComposition() { } else if (isDisplayConnected) { // The HWC doesn't support present fences, so use the refresh // timestamp instead. - const nsecs_t presentTime = - getHwComposer().getRefreshTimestamp(display->getPhysicalId()); + const nsecs_t presentTime = display->getRefreshTimestamp(); mAnimFrameTracker.setActualPresentTime(presentTime); } mAnimFrameTracker.advanceFrame(); @@ -2361,6 +2366,24 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { // here the transaction has been committed } +DisplayModes SurfaceFlinger::loadSupportedDisplayModes(PhysicalDisplayId displayId) const { + const auto hwcModes = getHwComposer().getModes(displayId); + DisplayModes modes; + size_t nextModeId = 0; + for (const auto& hwcMode : hwcModes) { + modes.push_back(DisplayMode::Builder(hwcMode.hwcId) + .setId(DisplayModeId{nextModeId++}) + .setWidth(hwcMode.width) + .setHeight(hwcMode.height) + .setVsyncPeriod(hwcMode.vsyncPeriod) + .setDpiX(hwcMode.dpiX) + .setDpiY(hwcMode.dpiY) + .setConfigGroup(hwcMode.configGroup) + .build()); + } + return modes; +} + void SurfaceFlinger::processDisplayHotplugEventsLocked() { for (const auto& event : mPendingHotplugEvents) { std::optional info = @@ -2374,8 +2397,14 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { const auto it = mPhysicalDisplayTokens.find(displayId); if (event.connection == hal::Connection::CONNECTED) { - auto supportedModes = getHwComposer().getModes(displayId); - const auto activeMode = getHwComposer().getActiveMode(displayId); + auto supportedModes = loadSupportedDisplayModes(displayId); + const auto activeModeHwcId = getHwComposer().getActiveMode(displayId); + LOG_ALWAYS_FATAL_IF(!activeModeHwcId, "HWC returned no active config"); + + const auto activeMode = *std::find_if(supportedModes.begin(), supportedModes.end(), + [activeModeHwcId](const DisplayModePtr& mode) { + return mode->getHwcId() == *activeModeHwcId; + }); // TODO(b/175678215) Handle the case when activeMode is not in supportedModes if (it == mPhysicalDisplayTokens.end()) { @@ -2526,17 +2555,15 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( void SurfaceFlinger::processDisplayAdded(const wp& displayToken, const DisplayDeviceState& state) { - int width = 0; - int height = 0; + ui::Size resolution(0, 0); ui::PixelFormat pixelFormat = static_cast(PIXEL_FORMAT_UNKNOWN); if (state.physical) { - width = state.physical->activeMode->getWidth(); - height = state.physical->activeMode->getHeight(); + resolution = state.physical->activeMode->getSize(); pixelFormat = static_cast(PIXEL_FORMAT_RGBA_8888); } else if (state.surface != nullptr) { - int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width); + int status = state.surface->query(NATIVE_WINDOW_WIDTH, &resolution.width); ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status); - status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height); + status = state.surface->query(NATIVE_WINDOW_HEIGHT, &resolution.height); ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status); int intPixelFormat; status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat); @@ -2553,7 +2580,7 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, if (const auto& physical = state.physical) { builder.setPhysical({physical->id, physical->type}); } - builder.setPixels(ui::Size(width, height)); + builder.setPixels(resolution); builder.setPixelFormat(pixelFormat); builder.setIsSecure(state.isSecure); builder.setLayerStackId(state.layerStack); @@ -2588,7 +2615,8 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, const auto physicalId = PhysicalDisplayId::tryCast(displayId); LOG_FATAL_IF(!physicalId); displaySurface = new FramebufferSurface(getHwComposer(), *physicalId, bqConsumer, - maxGraphicsWidth, maxGraphicsHeight); + state.physical->activeMode->getSize(), + ui::Size(maxGraphicsWidth, maxGraphicsHeight)); producer = bqProducer; } @@ -4843,15 +4871,12 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co " gpu_to_cpu_unsupported : %d\n", mTransactionFlags.load(), !mGpuToCpuSupported); - if (const auto displayId = getInternalDisplayIdLocked(); - displayId && getHwComposer().isConnected(*displayId)) { - const auto activeConfig = getHwComposer().getActiveMode(*displayId); + if (const auto display = getDefaultDisplayDeviceLocked()) { std::string fps, xDpi, yDpi; - if (activeConfig) { - const auto vsyncPeriod = getHwComposer().getDisplayVsyncPeriod(*displayId); - fps = base::StringPrintf("%s", to_string(Fps::fromPeriodNsecs(vsyncPeriod)).c_str()); - xDpi = base::StringPrintf("%.2f", activeConfig->getDpiX()); - yDpi = base::StringPrintf("%.2f", activeConfig->getDpiY()); + if (const auto activeMode = display->getActiveMode()) { + fps = to_string(activeMode->getFps()); + xDpi = base::StringPrintf("%.2f", activeMode->getDpiX()); + yDpi = base::StringPrintf("%.2f", activeMode->getDpiY()); } else { fps = "unknown"; xDpi = "unknown"; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index ec73b091bb..5b2d1c3c98 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -897,6 +897,7 @@ private: /* * Display management */ + DisplayModes loadSupportedDisplayModes(PhysicalDisplayId) const; sp setupNewDisplayDeviceInternal( const wp& displayToken, std::shared_ptr compositionDisplay, diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index bd49728215..e0cb7c8750 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -63,9 +63,7 @@ namespace { // Mock test helpers using ::testing::_; -using ::testing::AtLeast; using ::testing::DoAll; -using ::testing::Invoke; using ::testing::Return; using ::testing::SetArgPointee; @@ -74,9 +72,11 @@ using Attribute = V2_4::IComposerClient::Attribute; using Display = V2_1::Display; /////////////////////////////////////////////// - -constexpr PhysicalDisplayId kPrimaryDisplayId = PhysicalDisplayId::fromPort(PRIMARY_DISPLAY); -constexpr PhysicalDisplayId kExternalDisplayId = PhysicalDisplayId::fromPort(EXTERNAL_DISPLAY); +constexpr PhysicalDisplayId physicalIdFromHwcDisplayId(Display hwcId) { + return PhysicalDisplayId::fromPort(hwcId); +} +constexpr PhysicalDisplayId kPrimaryDisplayId = physicalIdFromHwcDisplayId(PRIMARY_DISPLAY); +constexpr PhysicalDisplayId kExternalDisplayId = physicalIdFromHwcDisplayId(EXTERNAL_DISPLAY); struct TestColor { public: @@ -158,7 +158,7 @@ protected: self->mReceivedDisplayEvents.push_back(buffer[i]); } } - ALOGD_IF(n < 0, "Error reading events (%s)\n", strerror(-n)); + ALOGD_IF(n < 0, "Error reading events (%s)", strerror(-n)); return 1; } @@ -174,7 +174,7 @@ protected: void setExpectationsForConfigs(Display display, std::vector testConfigs, Config activeConfig, V2_4::VsyncPeriodNanos defaultVsyncPeriod) { std::vector configIds; - for (int i = 0; i < testConfigs.size(); i++) { + for (size_t i = 0; i < testConfigs.size(); i++) { configIds.push_back(testConfigs[i].id); EXPECT_CALL(*mMockComposer, @@ -269,10 +269,10 @@ protected: mMockComposer = nullptr; } - void waitForDisplayTransaction() { + void waitForDisplayTransaction(Display display) { // Both a refresh and a vsync event are needed to apply pending display // transactions. - mFakeComposerClient->refreshDisplay(EXTERNAL_DISPLAY); + mFakeComposerClient->refreshDisplay(display); mFakeComposerClient->runVSyncAndWait(); // Extra vsync and wait to avoid a 10% flake due to a race. @@ -291,7 +291,7 @@ protected: mReceivedDisplayEvents.pop_front(); ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, - "event hotplug: displayId %s, connected %d\t", + "event hotplug: displayId %s, connected %d", to_string(event.header.displayId).c_str(), event.hotplug.connected); if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG && @@ -314,7 +314,7 @@ protected: mReceivedDisplayEvents.pop_front(); ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, - "event config: displayId %s, configId %d\t", + "event config: displayId %s, configId %d", to_string(event.header.displayId).c_str(), event.config.configId); if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED && @@ -341,7 +341,7 @@ protected: mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY, V2_1::IComposerCallback::Connection::CONNECTED); - waitForDisplayTransaction(); + waitForDisplayTransaction(EXTERNAL_DISPLAY); EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true)); { @@ -372,7 +372,7 @@ protected: mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY, V2_1::IComposerCallback::Connection::DISCONNECTED); - waitForDisplayTransaction(); + waitForDisplayTransaction(EXTERNAL_DISPLAY); mFakeComposerClient->clearFrames(); EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false)); @@ -403,7 +403,7 @@ protected: mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY, V2_1::IComposerCallback::Connection::CONNECTED); - waitForDisplayTransaction(); + waitForDisplayTransaction(EXTERNAL_DISPLAY); EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true)); const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId); @@ -456,7 +456,7 @@ protected: config.refreshRate, config.refreshRate, config.refreshRate)); - waitForDisplayTransaction(); + waitForDisplayTransaction(EXTERNAL_DISPLAY); EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i)); break; } @@ -487,7 +487,7 @@ protected: mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY, V2_1::IComposerCallback::Connection::DISCONNECTED); - waitForDisplayTransaction(); + waitForDisplayTransaction(EXTERNAL_DISPLAY); mFakeComposerClient->clearFrames(); EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false)); } @@ -510,7 +510,7 @@ protected: mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY, V2_1::IComposerCallback::Connection::CONNECTED); - waitForDisplayTransaction(); + waitForDisplayTransaction(EXTERNAL_DISPLAY); EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true)); const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId); @@ -562,7 +562,7 @@ protected: config.refreshRate, config.refreshRate, config.refreshRate)); - waitForDisplayTransaction(); + waitForDisplayTransaction(EXTERNAL_DISPLAY); EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i)); break; } @@ -593,7 +593,7 @@ protected: mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY, V2_1::IComposerCallback::Connection::DISCONNECTED); - waitForDisplayTransaction(); + waitForDisplayTransaction(EXTERNAL_DISPLAY); mFakeComposerClient->clearFrames(); EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false)); } @@ -626,7 +626,7 @@ protected: mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY, V2_1::IComposerCallback::Connection::CONNECTED); - waitForDisplayTransaction(); + waitForDisplayTransaction(EXTERNAL_DISPLAY); EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true)); const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId); @@ -669,7 +669,7 @@ protected: .WillOnce(Return(V2_1::Error::NONE)); } - for (int i = 0; i < configs.size(); i++) { + for (size_t i = 0; i < configs.size(); i++) { const auto& config = configs[i]; if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) { EXPECT_EQ(NO_ERROR, @@ -679,7 +679,7 @@ protected: configs[i].refreshRate, configs[i].refreshRate, configs[i].refreshRate)); - waitForDisplayTransaction(); + waitForDisplayTransaction(EXTERNAL_DISPLAY); EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i)); break; } @@ -726,7 +726,7 @@ protected: config.refreshRate, config.refreshRate, config.refreshRate)); - waitForDisplayTransaction(); + waitForDisplayTransaction(EXTERNAL_DISPLAY); EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i)); break; } @@ -773,7 +773,7 @@ protected: config.refreshRate, config.refreshRate, config.refreshRate)); - waitForDisplayTransaction(); + waitForDisplayTransaction(EXTERNAL_DISPLAY); EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i)); break; } @@ -804,7 +804,7 @@ protected: mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY, V2_1::IComposerCallback::Connection::DISCONNECTED); - waitForDisplayTransaction(); + waitForDisplayTransaction(EXTERNAL_DISPLAY); mFakeComposerClient->clearFrames(); EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false)); } @@ -815,7 +815,7 @@ protected: mFakeComposerClient->hotplugDisplay(PRIMARY_DISPLAY, V2_1::IComposerCallback::Connection::DISCONNECTED); - waitForDisplayTransaction(); + waitForDisplayTransaction(PRIMARY_DISPLAY); EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, false)); { @@ -840,7 +840,7 @@ protected: mFakeComposerClient->hotplugDisplay(PRIMARY_DISPLAY, V2_1::IComposerCallback::Connection::CONNECTED); - waitForDisplayTransaction(); + waitForDisplayTransaction(PRIMARY_DISPLAY); EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, true)); @@ -856,6 +856,121 @@ protected: } } + void Test_SubsequentHotplugConnectUpdatesDisplay(Display hwcDisplayId) { + ALOGD("DisplayTest::Test_SubsequentHotplugConnectUpdatesDisplay"); + + // Send a hotplug connected event to set up the initial display modes. + // The primary display is already connected so this will update it. + // If we're running the test of an external display this will create it. + setExpectationsForConfigs(hwcDisplayId, + {{.id = 1, + .w = 800, + .h = 1600, + .vsyncPeriod = 11'111'111, + .group = 1}}, + /* activeConfig */ 1, 11'111'111); + + mFakeComposerClient->hotplugDisplay(hwcDisplayId, + V2_1::IComposerCallback::Connection::CONNECTED); + waitForDisplayTransaction(hwcDisplayId); + EXPECT_TRUE(waitForHotplugEvent(hwcDisplayId, true)); + + const auto displayId = physicalIdFromHwcDisplayId(hwcDisplayId); + const auto display = SurfaceComposerClient::getPhysicalDisplayToken(displayId); + EXPECT_FALSE(display == nullptr); + + // Verify that the active mode and the supported moded are updated + { + DisplayConfig config; + EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config)); + EXPECT_EQ(ui::Size(800, 1600), config.resolution); + EXPECT_EQ(1e9f / 11'111'111, config.refreshRate); + + Vector configs; + EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs)); + EXPECT_EQ(configs.size(), 1); + } + + // Send another hotplug connected event + setExpectationsForConfigs(hwcDisplayId, + { + {.id = 1, + .w = 800, + .h = 1600, + .vsyncPeriod = 16'666'666, + .group = 1}, + {.id = 2, + .w = 800, + .h = 1600, + .vsyncPeriod = 11'111'111, + .group = 1}, + {.id = 3, + .w = 800, + .h = 1600, + .vsyncPeriod = 8'333'333, + .group = 1}, + }, + /* activeConfig */ 1, 16'666'666); + + mFakeComposerClient->hotplugDisplay(hwcDisplayId, + V2_1::IComposerCallback::Connection::CONNECTED); + waitForDisplayTransaction(hwcDisplayId); + EXPECT_TRUE(waitForHotplugEvent(hwcDisplayId, true)); + + // Verify that the active mode and the supported moded are updated + { + DisplayConfig config; + EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config)); + EXPECT_EQ(ui::Size(800, 1600), config.resolution); + EXPECT_EQ(1e9f / 16'666'666, config.refreshRate); + } + + Vector configs; + EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs)); + EXPECT_EQ(configs.size(), 3); + + EXPECT_EQ(ui::Size(800, 1600), configs[0].resolution); + EXPECT_EQ(1e9f / 16'666'666, configs[0].refreshRate); + + EXPECT_EQ(ui::Size(800, 1600), configs[1].resolution); + EXPECT_EQ(1e9f / 11'111'111, configs[1].refreshRate); + + EXPECT_EQ(ui::Size(800, 1600), configs[2].resolution); + EXPECT_EQ(1e9f / 8'333'333, configs[2].refreshRate); + + // Verify that we are able to switch to any of the modes + for (int i = configs.size() - 1; i >= 0; i--) { + const auto hwcId = i + 1; + // Set up HWC expectations for the mode change + if (mIs2_4Client) { + EXPECT_CALL(*mMockComposer, + setActiveConfigWithConstraints(hwcDisplayId, hwcId, _, _)) + .WillOnce(Return(V2_4::Error::NONE)); + } else { + EXPECT_CALL(*mMockComposer, setActiveConfig(hwcDisplayId, hwcId)) + .WillOnce(Return(V2_1::Error::NONE)); + } + + EXPECT_EQ(NO_ERROR, + SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false, + configs[i].refreshRate, + configs[i].refreshRate, + configs[i].refreshRate, + configs[i].refreshRate)); + // We need to refresh twice - once to apply the pending mode change request, + // and once to process the change. + waitForDisplayTransaction(hwcDisplayId); + waitForDisplayTransaction(hwcDisplayId); + EXPECT_TRUE(waitForConfigChangedEvent(hwcDisplayId, i)) + << "Failure while switching to mode " << i; + + DisplayConfig config; + EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config)); + EXPECT_EQ(ui::Size(800, 1600), config.resolution); + EXPECT_EQ(configs[i].refreshRate, config.refreshRate); + } + } + sp mFakeService; sp mComposerClient; @@ -911,6 +1026,14 @@ TEST_F(DisplayTest_2_1, HotplugPrimaryOneConfig) { Test_HotplugPrimaryDisplay(); } +TEST_F(DisplayTest_2_1, SubsequentHotplugConnectUpdatesPrimaryDisplay) { + Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY); +} + +TEST_F(DisplayTest_2_1, SubsequentHotplugConnectUpdatesExternalDisplay) { + Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY); +} + using DisplayTest_2_2 = DisplayTest; TEST_F(DisplayTest_2_2, HotplugOneConfig) { @@ -933,6 +1056,14 @@ TEST_F(DisplayTest_2_2, HotplugPrimaryOneConfig) { Test_HotplugPrimaryDisplay(); } +TEST_F(DisplayTest_2_2, SubsequentHotplugConnectUpdatesPrimaryDisplay) { + Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY); +} + +TEST_F(DisplayTest_2_2, SubsequentHotplugConnectUpdatesExternalDisplay) { + Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY); +} + using DisplayTest_2_3 = DisplayTest; TEST_F(DisplayTest_2_3, HotplugOneConfig) { @@ -955,6 +1086,14 @@ TEST_F(DisplayTest_2_3, HotplugPrimaryOneConfig) { Test_HotplugPrimaryDisplay(); } +TEST_F(DisplayTest_2_3, SubsequentHotplugConnectUpdatesPrimaryDisplay) { + Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY); +} + +TEST_F(DisplayTest_2_3, SubsequentHotplugConnectUpdatesExternalDisplay) { + Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY); +} + using DisplayTest_2_4 = DisplayTest; TEST_F(DisplayTest_2_4, HotplugOneConfig) { @@ -977,6 +1116,14 @@ TEST_F(DisplayTest_2_4, HotplugPrimaryOneConfig) { Test_HotplugPrimaryDisplay(); } +TEST_F(DisplayTest_2_4, SubsequentHotplugConnectUpdatesPrimaryDisplay) { + Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY); +} + +TEST_F(DisplayTest_2_4, SubsequentHotplugConnectUpdatesExternalDisplay) { + Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY); +} + //////////////////////////////////////////////// template diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index f2051d91c9..b696a6d51b 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -62,15 +62,9 @@ using hal::Transform; using testing::_; using testing::AtLeast; -using testing::Between; -using testing::ByMove; using testing::DoAll; -using testing::Field; -using testing::Invoke; using testing::IsNull; using testing::Mock; -using testing::NotNull; -using testing::Ref; using testing::Return; using testing::ReturnRef; using testing::SetArgPointee; @@ -86,7 +80,6 @@ constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID(42); constexpr int DEFAULT_DISPLAY_WIDTH = 1920; constexpr int DEFAULT_DISPLAY_HEIGHT = 1024; -constexpr int DEFAULT_CONFIG_ID = 0; constexpr int DEFAULT_TEXTURE_ID = 6000; constexpr int DEFAULT_LAYER_STACK = 7000; @@ -147,7 +140,7 @@ public: EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); EXPECT_CALL(*vsyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE)); + .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); constexpr ISchedulerCallback* kCallback = nullptr; @@ -548,12 +541,6 @@ struct BaseLayerProperties { setupLatchedBuffer(test, layer); } - static void setupBufferLayerPostFrameCallExpectations(CompositionTest* test) { - // BufferLayer::onPostComposition(), when there is no present fence - EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY, _)) - .WillOnce(DoAll(SetArgPointee<1>(DEFAULT_CONFIG_ID), Return(Error::NONE))); - } - static void setupHwcSetGeometryCallExpectations(CompositionTest* test) { if (!test->mDisplayOff) { // TODO: Coverage of other values @@ -632,8 +619,6 @@ struct BaseLayerProperties { .Times(1); EXPECT_CALL(*test->mComposer, setLayerBuffer(HWC_DISPLAY, HWC_LAYER, _, _, _)).Times(1); } - - setupBufferLayerPostFrameCallExpectations(test); } static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) { @@ -793,7 +778,6 @@ struct CommonSecureLayerProperties : public BaseLayerProperties static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) { setupInsecureREBufferCompositionCommonCallExpectations(test); - Base::setupBufferLayerPostFrameCallExpectations(test); } static void setupInsecureREBufferScreenshotCompositionCallExpectations(CompositionTest* test) { diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index 1e24c0a7de..6b8217087a 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -175,90 +175,5 @@ TEST_F(HWComposerLayerGenericMetadataTest, forwardsSupportedMetadata) { EXPECT_EQ(hal::Error::UNSUPPORTED, result); } -class HWComposerConfigsTest : public testing::Test { -public: - Hwc2::mock::Composer* mHal = new StrictMock(); - MockHWC2ComposerCallback mCallback; - - void setActiveConfig(Config config) { - EXPECT_CALL(*mHal, getActiveConfig(_, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(config), Return(V2_1::Error::NONE))); - } - - void setDisplayConfigs(std::vector configs) { - EXPECT_CALL(*mHal, getDisplayConfigs(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(configs), Return(V2_1::Error::NONE))); - EXPECT_CALL(*mHal, getDisplayAttribute(_, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<3>(1), Return(V2_1::Error::NONE))); - } - - void testSetActiveModeWithConstraintsCommon(bool isVsyncPeriodSwitchSupported); -}; - -void HWComposerConfigsTest::testSetActiveModeWithConstraintsCommon( - bool isVsyncPeriodSwitchSupported) { - EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0)); - EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector{})); - EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_)).WillOnce(Return(V2_4::Error::UNSUPPORTED)); - EXPECT_CALL(*mHal, registerCallback(_)); - EXPECT_CALL(*mHal, setVsyncEnabled(_, _)).WillRepeatedly(Return(V2_1::Error::NONE)); - EXPECT_CALL(*mHal, getDisplayIdentificationData(_, _, _)) - .WillRepeatedly(Return(V2_1::Error::UNSUPPORTED)); - EXPECT_CALL(*mHal, setClientTargetSlotCount(_)).WillRepeatedly(Return(V2_1::Error::NONE)); - - EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()) - .WillRepeatedly(Return(isVsyncPeriodSwitchSupported)); - - if (isVsyncPeriodSwitchSupported) { - EXPECT_CALL(*mHal, setActiveConfigWithConstraints(_, _, _, _)) - .WillRepeatedly(Return(V2_4::Error::NONE)); - } else { - EXPECT_CALL(*mHal, setActiveConfig(_, _)).WillRepeatedly(Return(V2_1::Error::NONE)); - } - - impl::HWComposer hwc{std::unique_ptr(mHal)}; - hwc.setConfiguration(&mCallback, 123); - - setDisplayConfigs({15}); - setActiveConfig(15); - - const auto physicalId = PhysicalDisplayId::fromPort(0); - const hal::HWDisplayId hwcId = 0; - hwc.allocatePhysicalDisplay(hwcId, physicalId); - - hal::VsyncPeriodChangeConstraints constraints; - constraints.desiredTimeNanos = systemTime(); - constraints.seamlessRequired = false; - - hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0}; - constexpr Config kConfigIndex = 0; - const auto status = - hwc.setActiveModeWithConstraints(physicalId, kConfigIndex, constraints, &timeline); - EXPECT_EQ(NO_ERROR, status); - - const std::vector kConfigs{7, 8, 9, 10, 11}; - // Change the set of supported modes. - setDisplayConfigs(kConfigs); - setActiveConfig(11); - hwc.onHotplug(hwcId, hal::Connection::CONNECTED); - hwc.allocatePhysicalDisplay(hwcId, physicalId); - - for (size_t configIndex = 0; configIndex < kConfigs.size(); configIndex++) { - const auto status = - hwc.setActiveModeWithConstraints(physicalId, - static_cast(configIndex), - constraints, &timeline); - EXPECT_EQ(NO_ERROR, status) << "Error when switching to config " << configIndex; - } -} - -TEST_F(HWComposerConfigsTest, setActiveModeWithConstraintsWithVsyncSwitchingSupported) { - testSetActiveModeWithConstraintsCommon(/*supported=*/true); -} - -TEST_F(HWComposerConfigsTest, setActiveModeWithConstraintsWithVsyncSwitchingNotSupported) { - testSetActiveModeWithConstraintsCommon(/*supported=*/false); -} - } // namespace } // namespace android \ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp index c5deb7ca07..abecd4b45b 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp @@ -144,7 +144,7 @@ void RefreshRateSelectionTest::setupScheduler() { EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); EXPECT_CALL(*vsyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE)); + .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), std::move(sfEventThread)); diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index e060df2420..a6d07d00ee 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -185,7 +185,7 @@ void SetFrameRateTest::setupScheduler() { EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); EXPECT_CALL(*vsyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE)); + .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), std::move(sfEventThread)); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp index 8552e15bb8..b713334f99 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp @@ -669,7 +669,7 @@ TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) { // -------------------------------------------------------------------- // Call Expectations - EXPECT_CALL(*displaySurface, resizeBuffers(newWidth, oldHeight)).Times(1); + EXPECT_CALL(*displaySurface, resizeBuffers(ui::Size(newWidth, oldHeight))).Times(1); // -------------------------------------------------------------------- // Invocation @@ -714,7 +714,7 @@ TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) { // -------------------------------------------------------------------- // Call Expectations - EXPECT_CALL(*displaySurface, resizeBuffers(oldWidth, newHeight)).Times(1); + EXPECT_CALL(*displaySurface, resizeBuffers(ui::Size(oldWidth, newHeight))).Times(1); // -------------------------------------------------------------------- // Invocation @@ -764,7 +764,7 @@ TEST_F(HandleTransactionLockedTest, processesDisplaySizeDisplayRectAndLayerStack // -------------------------------------------------------------------- // Call Expectations - EXPECT_CALL(*displaySurface, resizeBuffers(kNewWidth, kNewHeight)).Times(1); + EXPECT_CALL(*displaySurface, resizeBuffers(kNewSize.getSize())).Times(1); // -------------------------------------------------------------------- // Invocation diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 3be45e2712..16a76c2e4d 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -41,6 +41,7 @@ #include "SurfaceFlingerDefaultFactory.h" #include "SurfaceInterceptor.h" #include "TestableScheduler.h" +#include "mock/DisplayHardware/MockComposer.h" #include "mock/MockDisplayIdGenerator.h" #include "mock/MockFrameTimeline.h" #include "mock/MockFrameTracer.h" @@ -477,7 +478,7 @@ public: static constexpr hal::HWDisplayId DEFAULT_HWC_DISPLAY_ID = 1000; static constexpr int32_t DEFAULT_WIDTH = 1920; static constexpr int32_t DEFAULT_HEIGHT = 1280; - static constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666; + static constexpr int32_t DEFAULT_VSYNC_PERIOD = 16'666'666; static constexpr int32_t DEFAULT_CONFIG_GROUP = 7; static constexpr int32_t DEFAULT_DPI = 320; static constexpr hal::HWConfigId DEFAULT_ACTIVE_CONFIG = 0; @@ -502,8 +503,8 @@ public: return *this; } - auto& setRefreshRate(int32_t refreshRate) { - mRefreshRate = refreshRate; + auto& setVsyncPeriod(int32_t vsyncPeriod) { + mVsyncPeriod = vsyncPeriod; return *this; } @@ -532,7 +533,12 @@ public: return *this; } - void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) { + void inject(TestableSurfaceFlinger* flinger, Hwc2::mock::Composer* composer) { + using ::testing::_; + using ::testing::DoAll; + using ::testing::Return; + using ::testing::SetArgPointee; + static const std::unordered_set defaultCapabilities; if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities; @@ -547,15 +553,39 @@ public: display->setPowerMode(mPowerMode); flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = std::move(display); - auto config = DisplayMode::Builder(mActiveConfig) - .setWidth(mWidth) - .setHeight(mHeight) - .setVsyncPeriod(mRefreshRate) - .setDpiX(mDpiX) - .setDpiY(mDpiY) - .setConfigGroup(mConfigGroup) - .build(); - flinger->mutableHwcDisplayData()[mDisplayId].modes.push_back(config); + EXPECT_CALL(*composer, getDisplayConfigs(mHwcDisplayId, _)) + .WillRepeatedly( + DoAll(SetArgPointee<1>(std::vector{mActiveConfig}), + Return(hal::Error::NONE))); + + EXPECT_CALL(*composer, + getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::WIDTH, _)) + .WillRepeatedly(DoAll(SetArgPointee<3>(mWidth), Return(hal::Error::NONE))); + + EXPECT_CALL(*composer, + getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::HEIGHT, + _)) + .WillRepeatedly(DoAll(SetArgPointee<3>(mHeight), Return(hal::Error::NONE))); + + EXPECT_CALL(*composer, + getDisplayAttribute(mHwcDisplayId, mActiveConfig, + hal::Attribute::VSYNC_PERIOD, _)) + .WillRepeatedly( + DoAll(SetArgPointee<3>(mVsyncPeriod), Return(hal::Error::NONE))); + + EXPECT_CALL(*composer, + getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::DPI_X, _)) + .WillRepeatedly(DoAll(SetArgPointee<3>(mDpiX), Return(hal::Error::NONE))); + + EXPECT_CALL(*composer, + getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::DPI_Y, _)) + .WillRepeatedly(DoAll(SetArgPointee<3>(mDpiY), Return(hal::Error::NONE))); + + EXPECT_CALL(*composer, + getDisplayAttribute(mHwcDisplayId, mActiveConfig, + hal::Attribute::CONFIG_GROUP, _)) + .WillRepeatedly( + DoAll(SetArgPointee<3>(mConfigGroup), Return(hal::Error::NONE))); if (mHwcDisplayType == hal::DisplayType::PHYSICAL) { const auto physicalId = PhysicalDisplayId::tryCast(mDisplayId); @@ -581,10 +611,10 @@ public: hal::HWDisplayId mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID; int32_t mWidth = DEFAULT_WIDTH; int32_t mHeight = DEFAULT_HEIGHT; - int32_t mRefreshRate = DEFAULT_REFRESH_RATE; + int32_t mVsyncPeriod = DEFAULT_VSYNC_PERIOD; int32_t mDpiX = DEFAULT_DPI; - int32_t mConfigGroup = DEFAULT_CONFIG_GROUP; int32_t mDpiY = DEFAULT_DPI; + int32_t mConfigGroup = DEFAULT_CONFIG_GROUP; hal::HWConfigId mActiveConfig = DEFAULT_ACTIVE_CONFIG; hal::PowerMode mPowerMode = DEFAULT_POWER_MODE; const std::unordered_set* mCapabilities = nullptr; @@ -602,6 +632,21 @@ public: mHwcDisplayId(hwcDisplayId) { mCreationArgs.connectionType = connectionType; mCreationArgs.isPrimary = isPrimary; + + mActiveModeId = DisplayModeId(0); + DisplayModePtr activeMode = + DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG) + .setId(mActiveModeId) + .setWidth(FakeHwcDisplayInjector::DEFAULT_WIDTH) + .setHeight(FakeHwcDisplayInjector::DEFAULT_HEIGHT) + .setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD) + .setDpiX(FakeHwcDisplayInjector::DEFAULT_DPI) + .setDpiY(FakeHwcDisplayInjector::DEFAULT_DPI) + .setConfigGroup(0) + .build(); + + DisplayModes modes{activeMode}; + mCreationArgs.supportedModes = modes; } sp token() const { return mDisplayToken; } @@ -624,6 +669,16 @@ public: auto& mutableDisplayDevice() { return mFlinger.mutableDisplays()[mDisplayToken]; } + auto& setActiveMode(DisplayModeId mode) { + mActiveModeId = mode; + return *this; + } + + auto& setSupportedModes(DisplayModes mode) { + mCreationArgs.supportedModes = mode; + return *this; + } + auto& setNativeWindow(const sp& nativeWindow) { mCreationArgs.nativeWindow = nativeWindow; return *this; @@ -676,6 +731,9 @@ public: state.isSecure = mCreationArgs.isSecure; sp device = new DisplayDevice(mCreationArgs); + if (!device->isVirtual()) { + device->setActiveMode(mActiveModeId); + } mFlinger.mutableDisplays().emplace(mDisplayToken, device); mFlinger.mutableCurrentState().displays.add(mDisplayToken, state); mFlinger.mutableDrawingState().displays.add(mDisplayToken, state); @@ -692,6 +750,7 @@ public: sp mDisplayToken = new BBinder(); DisplayDeviceCreationArgs mCreationArgs; const std::optional mHwcDisplayId; + DisplayModeId mActiveModeId; }; private: diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 6d2f672bce..1ae42e7fdd 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -72,7 +72,7 @@ public: EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); EXPECT_CALL(*mVSyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE)); + .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); mFlinger.setupScheduler(std::unique_ptr(mVsyncController), std::unique_ptr(mVSyncTracker), -- cgit v1.2.3-59-g8ed1b From 7d436ecfc55ebf0ff69caa8d05a8f4eb63fb72f4 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 27 Jan 2021 20:40:50 -0800 Subject: Plumb refresh and render rates into shared timeline * Make the overridden frame rate from the Scheduler public so that SurfaceFlinger can access it for each uid. * Add the display refresh rate on each display frame * Add the application rendering rate on each SurfaceFrame created * If there is no application rendering rate, then set it to the display refresh rate. * Plumb all those metrics into TimeStats. * Change global metrics to increment for every SurfaceFrame instead of every DisplayFrame, so that the rendering rate dimension can be accurately captured. Bug: 172937287 Test: builds, boots, timestats dump Change-Id: Icfd4cecfdfa5d6c434661cab91c624eb08e8baea --- services/surfaceflinger/BufferLayer.cpp | 8 +- services/surfaceflinger/Fps.h | 2 +- .../surfaceflinger/FrameTimeline/FrameTimeline.cpp | 62 +++-- .../surfaceflinger/FrameTimeline/FrameTimeline.h | 15 +- services/surfaceflinger/Layer.cpp | 8 + services/surfaceflinger/Scheduler/Scheduler.h | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- services/surfaceflinger/TimeStats/TimeStats.cpp | 274 +++++++++++++-------- services/surfaceflinger/TimeStats/TimeStats.h | 48 ++-- .../TimeStats/timestatsproto/TimeStatsHelper.cpp | 80 +++--- .../include/timestatsproto/TimeStatsHelper.h | 98 ++++++-- .../tests/unittests/FrameTimelineTest.cpp | 178 ++++++------- .../tests/unittests/TimeStatsTest.cpp | 128 +++++----- .../tests/unittests/mock/MockFrameTimeline.h | 2 +- .../tests/unittests/mock/MockTimeStats.h | 10 +- 15 files changed, 513 insertions(+), 405 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index ec81ff7b14..097f7de891 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -366,8 +366,11 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, mFrameTracker.setFrameReadyTime(desiredPresentTime); } + const Fps refreshRate = mFlinger->mRefreshRateConfigs->getCurrentRefreshRate().getFps(); + const std::optional renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); if (presentFence->isValid()) { - mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence); + mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence, + refreshRate, renderRate); mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, presentFence, FrameTracer::FrameEvent::PRESENT_FENCE); mFrameTracker.setActualPresentFence(std::shared_ptr(presentFence)); @@ -378,7 +381,8 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, // The HWC doesn't support present fences, so use the refresh // timestamp instead. const nsecs_t actualPresentTime = display->getRefreshTimestamp(); - mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime); + mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime, + refreshRate, renderRate); mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, actualPresentTime, FrameTracer::FrameEvent::PRESENT_FENCE); diff --git a/services/surfaceflinger/Fps.h b/services/surfaceflinger/Fps.h index 38a9af0149..e9f06e5519 100644 --- a/services/surfaceflinger/Fps.h +++ b/services/surfaceflinger/Fps.h @@ -27,7 +27,7 @@ namespace android { // Value which represents "frames per second". This class is a wrapper around // float, providing some useful utilities, such as comparisons with tolerance -// and converting between period duruation and frequency. +// and converting between period duration and frequency. class Fps { public: static constexpr Fps fromPeriodNsecs(nsecs_t period) { return Fps(1e9f / period, period); } diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 3f833f4890..3f368c3955 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -320,6 +320,11 @@ void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchT mLastLatchTime = lastLatchTime; } +void SurfaceFrame::setRenderRate(Fps renderRate) { + std::lock_guard lock(mMutex); + mRenderRate = renderRate; +} + std::optional SurfaceFrame::getJankType() const { std::scoped_lock lock(mMutex); if (mActuals.presentTime == 0) { @@ -367,6 +372,9 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t StringAppendF(&result, "%s", indent.c_str()); StringAppendF(&result, "Owner Pid : %d\n", mOwnerPid); StringAppendF(&result, "%s", indent.c_str()); + StringAppendF(&result, "Scheduled rendering rate: %d fps\n", + mRenderRate ? mRenderRate->getIntValue() : 0); + StringAppendF(&result, "%s", indent.c_str()); StringAppendF(&result, "Present State : %s\n", toString(mPresentState).c_str()); StringAppendF(&result, "%s", indent.c_str()); StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str()); @@ -391,9 +399,10 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime); } -void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, - nsecs_t vsyncPeriod) { +void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate) { std::scoped_lock lock(mMutex); + + const Fps renderRate = mRenderRate ? *mRenderRate : refreshRate; if (mPresentState != PresentState::Presented) { // No need to update dropped buffers return; @@ -412,13 +421,13 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, mJankType = JankType::Unknown; mFramePresentMetadata = FramePresentMetadata::UnknownPresent; mFrameReadyMetadata = FrameReadyMetadata::UnknownFinish; - mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType); + mTimeStats->incrementJankyFrames(refreshRate, renderRate, mOwnerUid, mLayerName, mJankType); return; } const nsecs_t presentDelta = mActuals.presentTime - mPredictions.presentTime; const nsecs_t deadlineDelta = mActuals.endTime - mPredictions.endTime; - const nsecs_t deltaToVsync = std::abs(presentDelta) % vsyncPeriod; + const nsecs_t deltaToVsync = std::abs(presentDelta) % refreshRate.getPeriodNsecs(); if (deadlineDelta > mJankClassificationThresholds.deadlineThreshold) { mFrameReadyMetadata = FrameReadyMetadata::LateFinish; @@ -440,7 +449,8 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) { // Finish on time, Present early if (deltaToVsync < mJankClassificationThresholds.presentThreshold || - deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) { + deltaToVsync >= refreshRate.getPeriodNsecs() - + mJankClassificationThresholds.presentThreshold) { // Delta factor of vsync mJankType = JankType::SurfaceFlingerScheduling; } else { @@ -463,7 +473,8 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, mJankType |= displayFrameJankType; } else { if (deltaToVsync < mJankClassificationThresholds.presentThreshold || - deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) { + deltaToVsync >= refreshRate.getPeriodNsecs() - + mJankClassificationThresholds.presentThreshold) { // Delta factor of vsync mJankType |= JankType::SurfaceFlingerScheduling; } else { @@ -482,7 +493,7 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, } } } - mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType); + mTimeStats->incrementJankyFrames(refreshRate, renderRate, mOwnerUid, mLayerName, mJankType); } /** @@ -684,10 +695,10 @@ void FrameTimeline::addSurfaceFrame(std::shared_ptr surfaceFrame) mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame); } -void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsyncPeriod) { +void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, Fps refreshRate) { ATRACE_CALL(); std::scoped_lock lock(mMutex); - mCurrentDisplayFrame->onSfWakeUp(token, vsyncPeriod, + mCurrentDisplayFrame->onSfWakeUp(token, refreshRate, mTokenManager.getPredictionsForToken(token), wakeUpTime); } @@ -705,11 +716,11 @@ void FrameTimeline::DisplayFrame::addSurfaceFrame(std::shared_ptr mSurfaceFrames.push_back(surfaceFrame); } -void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, nsecs_t vsyncPeriod, +void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, Fps refreshRate, std::optional predictions, nsecs_t wakeUpTime) { mToken = token; - mVsyncPeriod = vsyncPeriod; + mRefreshRate = refreshRate; if (!predictions) { mPredictionState = PredictionState::Expired; } else { @@ -719,11 +730,6 @@ void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, nsecs_t vsyncPeriod, mSurfaceFlingerActuals.startTime = wakeUpTime; } -void FrameTimeline::DisplayFrame::setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod) { - mToken = token; - mVsyncPeriod = vsyncPeriod; -} - void FrameTimeline::DisplayFrame::setPredictions(PredictionState predictionState, TimelineItem predictions) { mPredictionState = predictionState; @@ -740,14 +746,13 @@ void FrameTimeline::DisplayFrame::setActualEndTime(nsecs_t actualEndTime) { void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) { mSurfaceFlingerActuals.presentTime = signalTime; - int32_t totalJankReasons = JankType::None; // Delta between the expected present and the actual present const nsecs_t presentDelta = mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime; // How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there // was a prediction error or not. - nsecs_t deltaToVsync = std::abs(presentDelta) % mVsyncPeriod; + nsecs_t deltaToVsync = std::abs(presentDelta) % mRefreshRate.getPeriodNsecs(); if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) { mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent : FramePresentMetadata::EarlyPresent; @@ -776,8 +781,8 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) { if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) { // Finish on time, Present early if (deltaToVsync < mJankClassificationThresholds.presentThreshold || - deltaToVsync >= - (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) { + deltaToVsync >= (mRefreshRate.getPeriodNsecs() - + mJankClassificationThresholds.presentThreshold)) { // Delta is a factor of vsync if its within the presentTheshold on either side // of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold // of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms. @@ -797,8 +802,8 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) { if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) { // Finish on time, Present late if (deltaToVsync < mJankClassificationThresholds.presentThreshold || - deltaToVsync >= - (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) { + deltaToVsync >= (mRefreshRate.getPeriodNsecs() - + mJankClassificationThresholds.presentThreshold)) { // Delta is a factor of vsync if its within the presentTheshold on either side // of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold // of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms. @@ -819,16 +824,9 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) { mJankType = JankType::Unknown; } } - totalJankReasons |= mJankType; - for (auto& surfaceFrame : mSurfaceFrames) { - surfaceFrame->onPresent(signalTime, mJankType, mVsyncPeriod); - auto surfaceFrameJankType = surfaceFrame->getJankType(); - if (surfaceFrameJankType != std::nullopt) { - totalJankReasons |= *surfaceFrameJankType; - } + surfaceFrame->onPresent(signalTime, mJankType, mRefreshRate); } - mTimeStats->incrementJankyFrames(totalJankReasons); } void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const { @@ -988,7 +986,7 @@ void FrameTimeline::DisplayFrame::dump(std::string& result, nsecs_t baseTime) co StringAppendF(&result, "Present Metadata : %s\n", toString(mFramePresentMetadata).c_str()); StringAppendF(&result, "Finish Metadata: %s\n", toString(mFrameReadyMetadata).c_str()); StringAppendF(&result, "Start Metadata: %s\n", toString(mFrameStartMetadata).c_str()); - std::chrono::nanoseconds vsyncPeriod(mVsyncPeriod); + std::chrono::nanoseconds vsyncPeriod(mRefreshRate.getPeriodNsecs()); StringAppendF(&result, "Vsync Period: %10f\n", std::chrono::duration(vsyncPeriod).count()); nsecs_t presentDelta = @@ -996,7 +994,7 @@ void FrameTimeline::DisplayFrame::dump(std::string& result, nsecs_t baseTime) co std::chrono::nanoseconds presentDeltaNs(std::abs(presentDelta)); StringAppendF(&result, "Present delta: %10f\n", std::chrono::duration(presentDeltaNs).count()); - std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mVsyncPeriod); + std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mRefreshRate.getPeriodNsecs()); StringAppendF(&result, "Present delta %% refreshrate: %10f\n", std::chrono::duration(deltaToVsync).count()); dumpTable(result, mSurfaceFlingerPredictions, mSurfaceFlingerActuals, "", mPredictionState, diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index 54e8efbc92..3ddd900145 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -16,6 +16,7 @@ #pragma once +#include <../Fps.h> #include <../TimeStats/TimeStats.h> #include #include @@ -175,13 +176,14 @@ public: void setActualQueueTime(nsecs_t actualQueueTime); void setAcquireFenceTime(nsecs_t acquireFenceTime); void setPresentState(PresentState presentState, nsecs_t lastLatchTime = 0); + void setRenderRate(Fps renderRate); // Functions called by FrameTimeline // BaseTime is the smallest timestamp in this SurfaceFrame. // Used for dumping all timestamps relative to the oldest, making it easy to read. nsecs_t getBaseTime() const; // Sets the actual present time, appropriate metadata and classifies the jank. - void onPresent(nsecs_t presentTime, int32_t displayFrameJankType, nsecs_t vsyncPeriod); + void onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate); // All the timestamps are dumped relative to the baseTime void dump(std::string& result, const std::string& indent, nsecs_t baseTime) const; // Emits a packet for perfetto tracing. The function body will be executed only if tracing is @@ -216,6 +218,8 @@ private: int32_t mJankType GUARDED_BY(mMutex) = JankType::None; // Indicates if this frame was composited by the GPU or not bool mGpuComposition GUARDED_BY(mMutex) = false; + // Rendering rate for this frame. + std::optional mRenderRate GUARDED_BY(mMutex); // Enum for the type of present FramePresentMetadata mFramePresentMetadata GUARDED_BY(mMutex) = FramePresentMetadata::UnknownPresent; @@ -255,7 +259,7 @@ public: // The first function called by SF for the current DisplayFrame. Fetches SF predictions based on // the token and sets the actualSfWakeTime for the current DisplayFrame. - virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) = 0; + virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) = 0; // Sets the sfPresentTime and finalizes the current DisplayFrame. Tracks the given present fence // until it's signaled, and updates the present timestamps of all presented SurfaceFrames in @@ -325,14 +329,13 @@ public: // is enabled. void trace(pid_t surfaceFlingerPid) const; // Sets the token, vsyncPeriod, predictions and SF start time. - void onSfWakeUp(int64_t token, nsecs_t vsyncPeriod, std::optional predictions, + void onSfWakeUp(int64_t token, Fps refreshRate, std::optional predictions, nsecs_t wakeUpTime); // Sets the appropriate metadata, classifies the jank and returns the classified jankType. void onPresent(nsecs_t signalTime); // Adds the provided SurfaceFrame to the current display frame. void addSurfaceFrame(std::shared_ptr surfaceFrame); - void setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod); void setPredictions(PredictionState predictionState, TimelineItem predictions); void setActualStartTime(nsecs_t actualStartTime); void setActualEndTime(nsecs_t actualEndTime); @@ -382,7 +385,7 @@ public: FrameStartMetadata mFrameStartMetadata = FrameStartMetadata::UnknownStart; // The refresh rate (vsync period) in nanoseconds as seen by SF during this DisplayFrame's // timeline - nsecs_t mVsyncPeriod = 0; + Fps mRefreshRate; // TraceCookieCounter is used to obtain the cookie for sendig trace packets to perfetto. // Using a reference here because the counter is owned by FrameTimeline, which outlives // DisplayFrame. @@ -398,7 +401,7 @@ public: const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName) override; void addSurfaceFrame(std::shared_ptr surfaceFrame) override; - void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) override; + void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override; void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr& presentFence) override; void parseArgs(const Vector& args, std::string& result) override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index df14003c75..f271df88a4 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1568,6 +1568,10 @@ std::shared_ptr Layer::createSurfaceFrameForTransac // For Transactions, the post time is considered to be both queue and acquire fence time. surfaceFrame->setActualQueueTime(postTime); surfaceFrame->setAcquireFenceTime(postTime); + const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); + if (fps) { + mSurfaceFrame->setRenderRate(*fps); + } onSurfaceFrameCreated(surfaceFrame); return surfaceFrame; } @@ -1579,6 +1583,10 @@ std::shared_ptr Layer::createSurfaceFrameForBuffer( debugName); // For buffers, acquire fence time will set during latch. surfaceFrame->setActualQueueTime(queueTime); + const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); + if (fps) { + mSurfaceFrame->setRenderRate(*fps); + } // TODO(b/178542907): Implement onSurfaceFrameCreated for BQLayer as well. onSurfaceFrameCreated(surfaceFrame); return surfaceFrame; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 5237516f17..0e9eba731a 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -174,6 +174,8 @@ public: // Stores the preferred refresh rate that an app should run at. // FrameRateOverride.refreshRateHz == 0 means no preference. void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mFrameRateOverridesMutex); + // Retrieves the overridden refresh rate for a given uid. + std::optional getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex); private: friend class TestableScheduler; @@ -236,7 +238,6 @@ private: Fps displayRefreshRate) REQUIRES(mFeatureStateLock) EXCLUDES(mFrameRateOverridesMutex); - std::optional getFrameRateOverride(uid_t uid) const EXCLUDES(mFrameRateOverridesMutex); impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const; // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f785cae6cb..4f274b6865 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1899,7 +1899,7 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT const bool tracePreComposition = mTracingEnabled && !mTracePostComposition; ConditionalLockGuard lock(mTracingLock, tracePreComposition); - mFrameTimeline->setSfWakeUp(vsyncId, frameStart, stats.vsyncPeriod); + mFrameTimeline->setSfWakeUp(vsyncId, frameStart, Fps::fromPeriodNsecs(stats.vsyncPeriod)); refreshNeeded = handleMessageTransaction(); refreshNeeded |= handleMessageInvalidate(); diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 5d387d68e8..c3f3671272 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -105,53 +105,63 @@ std::string frameRateVoteToProtoByteString(float refreshRate, int frameRateCompa AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) { std::lock_guard lock(mMutex); - if (mTimeStats.statsStart == 0) { + if (mTimeStats.statsStartLegacy == 0) { return AStatsManager_PULL_SKIP; } flushPowerTimeLocked(); - AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data); - mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime); - mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime()); - mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount); - std::string frameDurationBytes = - histogramToProtoByteString(mTimeStats.frameDuration.hist, mMaxPulledHistogramBuckets); - mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(), - frameDurationBytes.size()); - std::string renderEngineTimingBytes = - histogramToProtoByteString(mTimeStats.renderEngineTiming.hist, - mMaxPulledHistogramBuckets); - mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)renderEngineTimingBytes.c_str(), - renderEngineTimingBytes.size()); - - mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalFrames); - mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalJankyFrames); - mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFLongCpu); - mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFLongGpu); - mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalSFUnattributed); - mStatsDelegate->statsEventWriteInt32(event, mTimeStats.jankPayload.totalAppUnattributed); - - // TODO: populate these with real values - mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling - mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error - mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing - mStatsDelegate->statsEventWriteInt32(event, 0); // display_refresh_rate_bucket - std::string sfDeadlineMissedBytes = - histogramToProtoByteString(std::unordered_map(), - mMaxPulledHistogramBuckets); - mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)sfDeadlineMissedBytes.c_str(), - sfDeadlineMissedBytes.size()); // sf_deadline_misses - std::string sfPredictionErrorBytes = - histogramToProtoByteString(std::unordered_map(), - mMaxPulledHistogramBuckets); - mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)sfPredictionErrorBytes.c_str(), - sfPredictionErrorBytes.size()); // sf_prediction_errors - mStatsDelegate->statsEventWriteInt32(event, 0); // render_rate_bucket - mStatsDelegate->statsEventBuild(event); + for (const auto& globalSlice : mTimeStats.stats) { + AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data); + mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFramesLegacy); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFramesLegacy); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFramesLegacy); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTimeLegacy); + mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresentLegacy.totalTime()); + mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCountLegacy); + std::string frameDurationBytes = + histogramToProtoByteString(mTimeStats.frameDurationLegacy.hist, + mMaxPulledHistogramBuckets); + mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(), + frameDurationBytes.size()); + std::string renderEngineTimingBytes = + histogramToProtoByteString(mTimeStats.renderEngineTimingLegacy.hist, + mMaxPulledHistogramBuckets); + mStatsDelegate->statsEventWriteByteArray(event, + (const uint8_t*)renderEngineTimingBytes.c_str(), + renderEngineTimingBytes.size()); + + mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalFrames); + mStatsDelegate->statsEventWriteInt32(event, + globalSlice.second.jankPayload.totalJankyFrames); + mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongCpu); + mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFLongGpu); + mStatsDelegate->statsEventWriteInt32(event, + globalSlice.second.jankPayload.totalSFUnattributed); + mStatsDelegate->statsEventWriteInt32(event, + globalSlice.second.jankPayload.totalAppUnattributed); + + // TODO: populate these with real values + mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling + mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error + mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing + mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.displayRefreshRateBucket); + std::string sfDeadlineMissedBytes = + histogramToProtoByteString(std::unordered_map(), + mMaxPulledHistogramBuckets); + mStatsDelegate + ->statsEventWriteByteArray(event, (const uint8_t*)sfDeadlineMissedBytes.c_str(), + sfDeadlineMissedBytes.size()); // sf_deadline_misses + std::string sfPredictionErrorBytes = + histogramToProtoByteString(std::unordered_map(), + mMaxPulledHistogramBuckets); + mStatsDelegate + ->statsEventWriteByteArray(event, (const uint8_t*)sfPredictionErrorBytes.c_str(), + sfPredictionErrorBytes.size()); // sf_prediction_errors + mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.renderRateBucket); + mStatsDelegate->statsEventBuild(event); + } + clearGlobalLocked(); return AStatsManager_PULL_SUCCESS; @@ -161,8 +171,17 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventLis std::lock_guard lock(mMutex); std::vector dumpStats; - for (const auto& ele : mTimeStats.stats) { - dumpStats.push_back(&ele.second); + uint32_t numLayers = 0; + for (const auto& globalSlice : mTimeStats.stats) { + numLayers += globalSlice.second.stats.size(); + } + + dumpStats.reserve(numLayers); + + for (const auto& globalSlice : mTimeStats.stats) { + for (const auto& layerSlice : globalSlice.second.stats) { + dumpStats.push_back(&layerSlice.second); + } } std::sort(dumpStats.begin(), dumpStats.end(), @@ -208,8 +227,9 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventLis mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing - mStatsDelegate->statsEventWriteInt32(event, 0); // display_refresh_rate_bucket - mStatsDelegate->statsEventWriteInt32(event, 0); // render_rate_bucket + mStatsDelegate->statsEventWriteInt32( + event, layer->displayRefreshRateBucket); // display_refresh_rate_bucket + mStatsDelegate->statsEventWriteInt32(event, layer->renderRateBucket); // render_rate_bucket std::string frameRateVoteBytes = frameRateVoteToProtoByteString(0.0, 0, 0); mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameRateVoteBytes.c_str(), frameRateVoteBytes.size()); // set_frame_rate_vote @@ -310,7 +330,7 @@ void TimeStats::incrementTotalFrames() { ATRACE_CALL(); std::lock_guard lock(mMutex); - mTimeStats.totalFrames++; + mTimeStats.totalFramesLegacy++; } void TimeStats::incrementMissedFrames() { @@ -319,7 +339,7 @@ void TimeStats::incrementMissedFrames() { ATRACE_CALL(); std::lock_guard lock(mMutex); - mTimeStats.missedFrames++; + mTimeStats.missedFramesLegacy++; } void TimeStats::incrementClientCompositionFrames() { @@ -328,7 +348,7 @@ void TimeStats::incrementClientCompositionFrames() { ATRACE_CALL(); std::lock_guard lock(mMutex); - mTimeStats.clientCompositionFrames++; + mTimeStats.clientCompositionFramesLegacy++; } void TimeStats::incrementClientCompositionReusedFrames() { @@ -337,7 +357,7 @@ void TimeStats::incrementClientCompositionReusedFrames() { ATRACE_CALL(); std::lock_guard lock(mMutex); - mTimeStats.clientCompositionReusedFrames++; + mTimeStats.clientCompositionReusedFramesLegacy++; } void TimeStats::incrementRefreshRateSwitches() { @@ -346,7 +366,7 @@ void TimeStats::incrementRefreshRateSwitches() { ATRACE_CALL(); std::lock_guard lock(mMutex); - mTimeStats.refreshRateSwitches++; + mTimeStats.refreshRateSwitchesLegacy++; } void TimeStats::incrementCompositionStrategyChanges() { @@ -355,7 +375,7 @@ void TimeStats::incrementCompositionStrategyChanges() { ATRACE_CALL(); std::lock_guard lock(mMutex); - mTimeStats.compositionStrategyChanges++; + mTimeStats.compositionStrategyChangesLegacy++; } void TimeStats::recordDisplayEventConnectionCount(int32_t count) { @@ -364,8 +384,8 @@ void TimeStats::recordDisplayEventConnectionCount(int32_t count) { ATRACE_CALL(); std::lock_guard lock(mMutex); - mTimeStats.displayEventConnectionsCount = - std::max(mTimeStats.displayEventConnectionsCount, count); + mTimeStats.displayEventConnectionsCountLegacy = + std::max(mTimeStats.displayEventConnectionsCountLegacy, count); } static int32_t msBetween(nsecs_t start, nsecs_t end) { @@ -381,7 +401,7 @@ void TimeStats::recordFrameDuration(nsecs_t startTime, nsecs_t endTime) { std::lock_guard lock(mMutex); if (mPowerTime.powerMode == PowerMode::ON) { - mTimeStats.frameDuration.insert(msBetween(startTime, endTime)); + mTimeStats.frameDurationLegacy.insert(msBetween(startTime, endTime)); } } @@ -444,12 +464,22 @@ bool TimeStats::recordReadyLocked(int32_t layerId, TimeRecord* timeRecord) { return true; } -void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId) { +static int32_t clampToSmallestBucket(Fps fps, size_t bucketWidth) { + return (fps.getIntValue() / bucketWidth) * bucketWidth; +} + +void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, + std::optional renderRate) { ATRACE_CALL(); LayerRecord& layerRecord = mTimeStatsTracker[layerId]; TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord; std::deque& timeRecords = layerRecord.timeRecords; + const int32_t refreshRateBucket = + clampToSmallestBucket(displayRefreshRate, REFRESH_RATE_BUCKET_WIDTH); + const int32_t renderRateBucket = + clampToSmallestBucket(renderRate ? *renderRate : displayRefreshRate, + RENDER_RATE_BUCKET_WIDTH); while (!timeRecords.empty()) { if (!recordReadyLocked(layerId, &timeRecords[0])) break; ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerId, @@ -458,11 +488,21 @@ void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId) { if (prevTimeRecord.ready) { uid_t uid = layerRecord.uid; const std::string& layerName = layerRecord.layerName; - if (!mTimeStats.stats.count({uid, layerName})) { - mTimeStats.stats[{uid, layerName}].uid = uid; - mTimeStats.stats[{uid, layerName}].layerName = layerName; + TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket}; + if (!mTimeStats.stats.count(timelineKey)) { + mTimeStats.stats[timelineKey].key = timelineKey; + } + + TimeStatsHelper::TimelineStats& displayStats = mTimeStats.stats[timelineKey]; + + TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName}; + if (!displayStats.stats.count(layerKey)) { + displayStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket; + displayStats.stats[layerKey].renderRateBucket = renderRateBucket; + displayStats.stats[layerKey].uid = uid; + displayStats.stats[layerKey].layerName = layerName; } - TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[{uid, layerName}]; + TimeStatsHelper::TimeStatsLayer& timeStatsLayer = displayStats.stats[layerKey]; timeStatsLayer.totalFrames++; timeStatsLayer.droppedFrames += layerRecord.droppedFrames; timeStatsLayer.lateAcquireFrames += layerRecord.lateAcquireFrames; @@ -524,8 +564,16 @@ static bool layerNameIsValid(const std::string& layerName) { } bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName) { - return mTimeStats.stats.count({uid, layerName}) > 0 || - mTimeStats.stats.size() < MAX_NUM_LAYER_STATS; + uint32_t layerRecords = 0; + for (const auto& record : mTimeStats.stats) { + if (record.second.stats.count({uid, layerName}) > 0) { + return true; + } + + layerRecords += record.second.stats.size(); + } + + return mTimeStats.stats.size() < MAX_NUM_LAYER_STATS; } void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, @@ -676,7 +724,8 @@ void TimeStats::setAcquireFence(int32_t layerId, uint64_t frameNumber, } } -void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) { +void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, + Fps displayRefreshRate, std::optional renderRate) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -695,11 +744,12 @@ void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t pr layerRecord.waitData++; } - flushAvailableRecordsToStatsLocked(layerId); + flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate); } void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, - const std::shared_ptr& presentFence) { + const std::shared_ptr& presentFence, + Fps displayRefreshRate, std::optional renderRate) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -719,7 +769,7 @@ void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, layerRecord.waitData++; } - flushAvailableRecordsToStatsLocked(layerId); + flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate); } template @@ -746,16 +796,8 @@ static void updateJankPayload(T& t, int32_t reasons) { } } -void TimeStats::incrementJankyFrames(int32_t reasons) { - if (!mEnabled.load()) return; - - ATRACE_CALL(); - std::lock_guard lock(mMutex); - - updateJankPayload(mTimeStats, reasons); -} - -void TimeStats::incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) { +void TimeStats::incrementJankyFrames(Fps refreshRate, std::optional renderRate, uid_t uid, + const std::string& layerName, int32_t reasons) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -772,16 +814,31 @@ void TimeStats::incrementJankyFrames(uid_t uid, const std::string& layerName, in // TimeStats will flush the first present fence for a layer *before* FrameTimeline does so that // the first jank record is not dropped. - bool useDefaultLayerKey = false; static const std::string kDefaultLayerName = "none"; - if (!mTimeStats.stats.count({uid, layerName})) { - mTimeStats.stats[{uid, kDefaultLayerName}].uid = uid; - mTimeStats.stats[{uid, kDefaultLayerName}].layerName = kDefaultLayerName; - useDefaultLayerKey = true; + + const int32_t refreshRateBucket = clampToSmallestBucket(refreshRate, REFRESH_RATE_BUCKET_WIDTH); + const int32_t renderRateBucket = + clampToSmallestBucket(renderRate ? *renderRate : refreshRate, RENDER_RATE_BUCKET_WIDTH); + const TimeStatsHelper::TimelineStatsKey timelineKey = {refreshRateBucket, renderRateBucket}; + + if (!mTimeStats.stats.count(timelineKey)) { + mTimeStats.stats[timelineKey].key = timelineKey; + } + + TimeStatsHelper::TimelineStats& timelineStats = mTimeStats.stats[timelineKey]; + + updateJankPayload(timelineStats, reasons); + + TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName}; + if (!timelineStats.stats.count(layerKey)) { + layerKey = {uid, kDefaultLayerName}; + timelineStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket; + timelineStats.stats[layerKey].renderRateBucket = renderRateBucket; + timelineStats.stats[layerKey].uid = uid; + timelineStats.stats[layerKey].layerName = kDefaultLayerName; } - TimeStatsHelper::TimeStatsLayer& timeStatsLayer = - mTimeStats.stats[{uid, useDefaultLayerKey ? kDefaultLayerName : layerName}]; + TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timelineStats.stats[layerKey]; updateJankPayload(timeStatsLayer, reasons); } @@ -823,7 +880,7 @@ void TimeStats::flushPowerTimeLocked() { switch (mPowerTime.powerMode) { case PowerMode::ON: - mTimeStats.displayOnTime += elapsedTime; + mTimeStats.displayOnTimeLegacy += elapsedTime; break; case PowerMode::OFF: case PowerMode::DOZE: @@ -852,10 +909,10 @@ void TimeStats::setPowerMode(PowerMode powerMode) { void TimeStats::recordRefreshRate(uint32_t fps, nsecs_t duration) { std::lock_guard lock(mMutex); - if (mTimeStats.refreshRateStats.count(fps)) { - mTimeStats.refreshRateStats[fps] += duration; + if (mTimeStats.refreshRateStatsLegacy.count(fps)) { + mTimeStats.refreshRateStatsLegacy[fps] += duration; } else { - mTimeStats.refreshRateStats.insert({fps, duration}); + mTimeStats.refreshRateStatsLegacy.insert({fps, duration}); } } @@ -881,7 +938,7 @@ void TimeStats::flushAvailableGlobalRecordsToStatsLocked() { msBetween(mGlobalRecord.prevPresentTime, curPresentTime); ALOGV("Global present2present[%d] prev[%" PRId64 "] curr[%" PRId64 "]", presentToPresentMs, mGlobalRecord.prevPresentTime, curPresentTime); - mTimeStats.presentToPresent.insert(presentToPresentMs); + mTimeStats.presentToPresentLegacy.insert(presentToPresentMs); } mGlobalRecord.prevPresentTime = curPresentTime; @@ -908,7 +965,7 @@ void TimeStats::flushAvailableGlobalRecordsToStatsLocked() { } const int32_t renderEngineMs = msBetween(duration.startTime, endNs); - mTimeStats.renderEngineTiming.insert(renderEngineMs); + mTimeStats.renderEngineTimingLegacy.insert(renderEngineMs); mGlobalRecord.renderEngineDurations.pop_front(); } @@ -951,7 +1008,7 @@ void TimeStats::enable() { std::lock_guard lock(mMutex); mEnabled.store(true); - mTimeStats.statsStart = static_cast(std::time(0)); + mTimeStats.statsStartLegacy = static_cast(std::time(0)); mPowerTime.prevTime = systemTime(); ALOGD("Enabled"); } @@ -964,7 +1021,7 @@ void TimeStats::disable() { std::lock_guard lock(mMutex); flushPowerTimeLocked(); mEnabled.store(false); - mTimeStats.statsEnd = static_cast(std::time(0)); + mTimeStats.statsEndLegacy = static_cast(std::time(0)); ALOGD("Disabled"); } @@ -977,21 +1034,20 @@ void TimeStats::clearAll() { void TimeStats::clearGlobalLocked() { ATRACE_CALL(); - mTimeStats.statsStart = (mEnabled.load() ? static_cast(std::time(0)) : 0); - mTimeStats.statsEnd = 0; - mTimeStats.totalFrames = 0; - mTimeStats.missedFrames = 0; - mTimeStats.clientCompositionFrames = 0; - mTimeStats.clientCompositionReusedFrames = 0; - mTimeStats.refreshRateSwitches = 0; - mTimeStats.compositionStrategyChanges = 0; - mTimeStats.displayEventConnectionsCount = 0; - mTimeStats.displayOnTime = 0; - mTimeStats.presentToPresent.hist.clear(); - mTimeStats.frameDuration.hist.clear(); - mTimeStats.renderEngineTiming.hist.clear(); - mTimeStats.jankPayload = TimeStatsHelper::JankPayload(); - mTimeStats.refreshRateStats.clear(); + mTimeStats.statsStartLegacy = (mEnabled.load() ? static_cast(std::time(0)) : 0); + mTimeStats.statsEndLegacy = 0; + mTimeStats.totalFramesLegacy = 0; + mTimeStats.missedFramesLegacy = 0; + mTimeStats.clientCompositionFramesLegacy = 0; + mTimeStats.clientCompositionReusedFramesLegacy = 0; + mTimeStats.refreshRateSwitchesLegacy = 0; + mTimeStats.compositionStrategyChangesLegacy = 0; + mTimeStats.displayEventConnectionsCountLegacy = 0; + mTimeStats.displayOnTimeLegacy = 0; + mTimeStats.presentToPresentLegacy.hist.clear(); + mTimeStats.frameDurationLegacy.hist.clear(); + mTimeStats.renderEngineTimingLegacy.hist.clear(); + mTimeStats.refreshRateStatsLegacy.clear(); mPowerTime.prevTime = systemTime(); mGlobalRecord.prevPresentTime = 0; mGlobalRecord.presentFences.clear(); @@ -1014,11 +1070,11 @@ void TimeStats::dump(bool asProto, std::optional maxLayers, std::strin ATRACE_CALL(); std::lock_guard lock(mMutex); - if (mTimeStats.statsStart == 0) { + if (mTimeStats.statsStartLegacy == 0) { return; } - mTimeStats.statsEnd = static_cast(std::time(0)); + mTimeStats.statsEndLegacy = static_cast(std::time(0)); flushPowerTimeLocked(); diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index df40ef6933..e76849f7dc 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -27,12 +27,13 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" +#include <../Fps.h> +#include #include #include #include #include #include -#include #include #include #include @@ -108,23 +109,22 @@ public: const std::shared_ptr& acquireFence) = 0; // SetPresent{Time, Fence} are not expected to be called in the critical // rendering path, as they flush prior fences if those fences have fired. - virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) = 0; + virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, + Fps displayRefreshRate, std::optional renderRate) = 0; virtual void setPresentFence(int32_t layerId, uint64_t frameNumber, - const std::shared_ptr& presentFence) = 0; - - // Increments janky frames, tracked globally. Because FrameTimeline is the infrastructure - // responsible for computing jank in the system, this is expected to be called from - // FrameTimeline, rather than directly from SurfaceFlinger or individual layers. If there are no - // jank reasons, then total frames are incremented but jank is not, for accurate accounting of - // janky frames. - virtual void incrementJankyFrames(int32_t reasons) = 0; - // Increments janky frames, blamed to the provided {uid, layerName} key, with JankMetadata as - // supplementary reasons for the jank. Because FrameTimeline is the infrastructure responsible - // for computing jank in the system, this is expected to be called from FrameTimeline, rather - // than directly from SurfaceFlinger or individual layers. - // If there are no jank reasons, then total frames are incremented but jank is not, for accurate + const std::shared_ptr& presentFence, + Fps displayRefreshRate, std::optional renderRate) = 0; + + // Increments janky frames, blamed to the provided {refreshRate, renderRate, uid, layerName} + // key, with JankMetadata as supplementary reasons for the jank. Because FrameTimeline is the + // infrastructure responsible for computing jank in the system, this is expected to be called + // from FrameTimeline, rather than directly from SurfaceFlinger or individual layers. If there + // are no jank reasons, then total frames are incremented but jank is not, for accurate // accounting of janky frames. - virtual void incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) = 0; + // When these frame counts are incremented, these are also aggregated into a global reporting + // packet to help with data validation and assessing of overall device health. + virtual void incrementJankyFrames(Fps refreshRate, std::optional renderRate, uid_t uid, + const std::string& layerName, int32_t reasons) = 0; // Clean up the layer record virtual void onDestroy(int32_t layerId) = 0; // If SF skips or rejects a buffer, remove the corresponding TimeRecord. @@ -268,11 +268,13 @@ public: void setAcquireTime(int32_t layerId, uint64_t frameNumber, nsecs_t acquireTime) override; void setAcquireFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& acquireFence) override; - void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) override; + void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, + Fps displayRefreshRate, std::optional renderRate) override; void setPresentFence(int32_t layerId, uint64_t frameNumber, - const std::shared_ptr& presentFence) override; - void incrementJankyFrames(int32_t reasons) override; - void incrementJankyFrames(uid_t uid, const std::string& layerName, int32_t reasons) override; + const std::shared_ptr& presentFence, Fps displayRefreshRate, + std::optional renderRate) override; + void incrementJankyFrames(Fps refreshRate, std::optional renderRate, uid_t uid, + const std::string& layerName, int32_t reasons) override; // Clean up the layer record void onDestroy(int32_t layerId) override; // If SF skips or rejects a buffer, remove the corresponding TimeRecord. @@ -293,7 +295,8 @@ private: AStatsManager_PullAtomCallbackReturn populateGlobalAtom(AStatsEventList* data); AStatsManager_PullAtomCallbackReturn populateLayerAtom(AStatsEventList* data); bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord); - void flushAvailableRecordsToStatsLocked(int32_t layerId); + void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, + std::optional renderRate); void flushPowerTimeLocked(); void flushAvailableGlobalRecordsToStatsLocked(); bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName); @@ -314,6 +317,9 @@ private: GlobalRecord mGlobalRecord; static const size_t MAX_NUM_LAYER_RECORDS = 200; + + static const size_t REFRESH_RATE_BUCKET_WIDTH = 30; + static const size_t RENDER_RATE_BUCKET_WIDTH = REFRESH_RATE_BUCKET_WIDTH; static const size_t MAX_NUM_LAYER_STATS = 200; static const size_t MAX_NUM_PULLED_LAYERS = MAX_NUM_LAYER_STATS; std::unique_ptr mStatsDelegate = std::make_unique(); diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp index 0fb748f1a6..df7be1ff50 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp +++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp @@ -90,6 +90,8 @@ std::string TimeStatsHelper::JankPayload::toString() const { std::string TimeStatsHelper::TimeStatsLayer::toString() const { std::string result = "\n"; + StringAppendF(&result, "displayRefreshRate = %d fps\n", displayRefreshRateBucket); + StringAppendF(&result, "renderRate = %d fps\n", renderRateBucket); StringAppendF(&result, "uid = %d\n", uid); StringAppendF(&result, "layerName = %s\n", layerName.c_str()); StringAppendF(&result, "packageName = %s\n", packageName.c_str()); @@ -115,35 +117,45 @@ std::string TimeStatsHelper::TimeStatsLayer::toString() const { std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional maxLayers) const { std::string result = "SurfaceFlinger TimeStats:\n"; - StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStart); - StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEnd); - StringAppendF(&result, "totalFrames = %d\n", totalFrames); - StringAppendF(&result, "missedFrames = %d\n", missedFrames); - StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames); - StringAppendF(&result, "clientCompositionReusedFrames = %d\n", clientCompositionReusedFrames); - StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitches); - StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChanges); - StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime); - result.append("Global aggregated jank payload:\n"); - result.append(jankPayload.toString()); + result.append("Legacy stats are as follows:\n"); + StringAppendF(&result, "statsStart = %" PRId64 "\n", statsStartLegacy); + StringAppendF(&result, "statsEnd = %" PRId64 "\n", statsEndLegacy); + StringAppendF(&result, "totalFrames = %d\n", totalFramesLegacy); + StringAppendF(&result, "missedFrames = %d\n", missedFramesLegacy); + StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFramesLegacy); + StringAppendF(&result, "clientCompositionReusedFrames = %d\n", + clientCompositionReusedFramesLegacy); + StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitchesLegacy); + StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChangesLegacy); + StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTimeLegacy); StringAppendF(&result, "displayConfigStats is as below:\n"); - for (const auto& [fps, duration] : refreshRateStats) { + for (const auto& [fps, duration] : refreshRateStatsLegacy) { StringAppendF(&result, "%dfps = %ldms\n", fps, ns2ms(duration)); } result.back() = '\n'; - StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime()); + StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresentLegacy.totalTime()); StringAppendF(&result, "presentToPresent histogram is as below:\n"); - result.append(presentToPresent.toString()); - const float averageFrameDuration = frameDuration.averageTime(); + result.append(presentToPresentLegacy.toString()); + const float averageFrameDuration = frameDurationLegacy.averageTime(); StringAppendF(&result, "averageFrameDuration = %.3f ms\n", std::isnan(averageFrameDuration) ? 0.0f : averageFrameDuration); StringAppendF(&result, "frameDuration histogram is as below:\n"); - result.append(frameDuration.toString()); - const float averageRenderEngineTiming = renderEngineTiming.averageTime(); + result.append(frameDurationLegacy.toString()); + const float averageRenderEngineTiming = renderEngineTimingLegacy.averageTime(); StringAppendF(&result, "averageRenderEngineTiming = %.3f ms\n", std::isnan(averageRenderEngineTiming) ? 0.0f : averageRenderEngineTiming); StringAppendF(&result, "renderEngineTiming histogram is as below:\n"); - result.append(renderEngineTiming.toString()); + result.append(renderEngineTimingLegacy.toString()); + + result.append("\nGlobal aggregated jank payload (Timeline stats):"); + for (const auto& ele : stats) { + result.append("\n"); + StringAppendF(&result, "displayRefreshRate = %d fps\n", + ele.second.key.displayRefreshRateBucket); + StringAppendF(&result, "renderRate = %d fps\n", ele.second.key.renderRateBucket); + result.append(ele.second.jankPayload.toString()); + } + const auto dumpStats = generateDumpStats(maxLayers); for (const auto& ele : dumpStats) { result.append(ele->toString()); @@ -173,30 +185,30 @@ SFTimeStatsLayerProto TimeStatsHelper::TimeStatsLayer::toProto() const { SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto( std::optional maxLayers) const { SFTimeStatsGlobalProto globalProto; - globalProto.set_stats_start(statsStart); - globalProto.set_stats_end(statsEnd); - globalProto.set_total_frames(totalFrames); - globalProto.set_missed_frames(missedFrames); - globalProto.set_client_composition_frames(clientCompositionFrames); - globalProto.set_display_on_time(displayOnTime); - for (const auto& ele : refreshRateStats) { + globalProto.set_stats_start(statsStartLegacy); + globalProto.set_stats_end(statsEndLegacy); + globalProto.set_total_frames(totalFramesLegacy); + globalProto.set_missed_frames(missedFramesLegacy); + globalProto.set_client_composition_frames(clientCompositionFramesLegacy); + globalProto.set_display_on_time(displayOnTimeLegacy); + for (const auto& ele : refreshRateStatsLegacy) { SFTimeStatsDisplayConfigBucketProto* configBucketProto = globalProto.add_display_config_stats(); SFTimeStatsDisplayConfigProto* configProto = configBucketProto->mutable_config(); configProto->set_fps(ele.first); configBucketProto->set_duration_millis(ns2ms(ele.second)); } - for (const auto& histEle : presentToPresent.hist) { + for (const auto& histEle : presentToPresentLegacy.hist) { SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present(); histProto->set_time_millis(histEle.first); histProto->set_frame_count(histEle.second); } - for (const auto& histEle : frameDuration.hist) { + for (const auto& histEle : frameDurationLegacy.hist) { SFTimeStatsHistogramBucketProto* histProto = globalProto.add_frame_duration(); histProto->set_time_millis(histEle.first); histProto->set_frame_count(histEle.second); } - for (const auto& histEle : renderEngineTiming.hist) { + for (const auto& histEle : renderEngineTimingLegacy.hist) { SFTimeStatsHistogramBucketProto* histProto = globalProto.add_render_engine_timing(); histProto->set_time_millis(histEle.first); histProto->set_frame_count(histEle.second); @@ -212,8 +224,18 @@ SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto( std::vector TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional maxLayers) const { std::vector dumpStats; + + int numLayers = 0; + for (const auto& ele : stats) { + numLayers += ele.second.stats.size(); + } + + dumpStats.reserve(numLayers); + for (const auto& ele : stats) { - dumpStats.push_back(&ele.second); + for (const auto& layerEle : ele.second.stats) { + dumpStats.push_back(&layerEle.second); + } } std::sort(dumpStats.begin(), dumpStats.end(), diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h index 033eb5dcd9..0144abc02f 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h +++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h @@ -57,6 +57,8 @@ public: uid_t uid; std::string layerName; std::string packageName; + int32_t displayRefreshRateBucket = 0; + int32_t renderRateBucket = 0; int32_t totalFrames = 0; int32_t droppedFrames = 0; int32_t lateAcquireFrames = 0; @@ -68,32 +70,82 @@ public: SFTimeStatsLayerProto toProto() const; }; - class TimeStatsGlobal { - public: - int64_t statsStart = 0; - int64_t statsEnd = 0; - int32_t totalFrames = 0; - int32_t missedFrames = 0; - int32_t clientCompositionFrames = 0; - int32_t clientCompositionReusedFrames = 0; - int32_t refreshRateSwitches = 0; - int32_t compositionStrategyChanges = 0; - int32_t displayEventConnectionsCount = 0; - int64_t displayOnTime = 0; - Histogram presentToPresent; - Histogram frameDuration; - Histogram renderEngineTiming; - - struct StatsHasher { - size_t operator()(const std::pair& p) const { - // Normally this isn't a very good hash function due to symmetry reasons, - // but these are distinct types so this should be good enough - return std::hash{}(p.first) ^ std::hash{}(p.second); + // Lifted from SkiaGLRenderEngine's LinearEffect class. + // Which in turn was inspired by art/runtime/class_linker.cc + // Also this is what boost:hash_combine does so this is a pretty good hash. + static size_t HashCombine(size_t seed, size_t val) { + return seed ^ (val + 0x9e3779b9 + (seed << 6) + (seed >> 2)); + } + + struct TimelineStatsKey { + int32_t displayRefreshRateBucket = 0; + int32_t renderRateBucket = 0; + + struct Hasher { + size_t operator()(const TimelineStatsKey& key) const { + size_t result = std::hash{}(key.displayRefreshRateBucket); + return HashCombine(result, std::hash{}(key.renderRateBucket)); + } + }; + + bool operator==(const TimelineStatsKey& o) const { + return displayRefreshRateBucket == o.displayRefreshRateBucket && + renderRateBucket == o.renderRateBucket; + } + }; + + struct LayerStatsKey { + uid_t uid = 0; + std::string layerName; + + struct Hasher { + size_t operator()(const LayerStatsKey& key) const { + size_t result = std::hash{}(key.uid); + return HashCombine(result, std::hash{}(key.layerName)); } }; - std::unordered_map, TimeStatsLayer, StatsHasher> stats; - std::unordered_map refreshRateStats; + + bool operator==(const LayerStatsKey& o) const { + return uid == o.uid && layerName == o.layerName; + } + }; + + struct LayerStatsHasher { + size_t operator()(const std::pair& p) const { + // Normally this isn't a very good hash function due to symmetry reasons, + // but these are distinct types so this should be good enough + return std::hash{}(p.first) ^ std::hash{}(p.second); + } + }; + + struct TimelineStats { + TimelineStatsKey key; JankPayload jankPayload; + std::unordered_map stats; + }; + + class TimeStatsGlobal { + public: + // Note: these are all legacy statistics, we're keeping these around because a variety of + // systems and form-factors find these useful when comparing with older releases. However, + // the current recommendation is that the new timeline-based metrics are used, and the old + // ones are deprecated. + int64_t statsStartLegacy = 0; + int64_t statsEndLegacy = 0; + int32_t totalFramesLegacy = 0; + int32_t missedFramesLegacy = 0; + int32_t clientCompositionFramesLegacy = 0; + int32_t clientCompositionReusedFramesLegacy = 0; + int32_t refreshRateSwitchesLegacy = 0; + int32_t compositionStrategyChangesLegacy = 0; + int32_t displayEventConnectionsCountLegacy = 0; + int64_t displayOnTimeLegacy = 0; + Histogram presentToPresentLegacy; + Histogram frameDurationLegacy; + Histogram renderEngineTimingLegacy; + std::unordered_map refreshRateStatsLegacy; + + std::unordered_map stats; std::string toString(std::optional maxLayers) const; SFTimeStatsGlobalProto toProto(std::optional maxLayers) const; diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index 6e9f09bdaa..a53655d6fa 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -238,7 +238,6 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validInputEventId) { TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -249,14 +248,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { sLayerNameOne, sLayerNameOne); // Set up the display frame - mFrameTimeline->setSfWakeUp(token1, 20, 11); + mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(25, presentFence1); presentFence1->signalForTest(30); // Trigger a flush by calling setSfPresent for the next frame - mFrameTimeline->setSfWakeUp(token2, 50, 11); + mFrameTimeline->setSfWakeUp(token2, 50, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(55, presentFence2); auto& droppedSurfaceFrame = getSurfaceFrame(0, 0); @@ -265,10 +264,10 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { } TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); // Layer specific increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2); + EXPECT_CALL(*mTimeStats, + incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_)) + .Times(2); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); @@ -280,7 +279,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameTwo, sLayerNameTwo); - mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); + mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -301,7 +300,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { auto surfaceFrame3 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); - mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); + mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); surfaceFrame3->setPresentState(SurfaceFrame::PresentState::Dropped); mFrameTimeline->addSurfaceFrame(surfaceFrame3); mFrameTimeline->setSfPresent(56, presentFence2); @@ -318,11 +317,9 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { // Insert kMaxDisplayFrames' count of DisplayFrames to fill the deque int frameTimeFactor = 0; - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)) - .Times(static_cast(*maxDisplayFrames)); // Layer specific increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)) + EXPECT_CALL(*mTimeStats, + incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_)) .Times(static_cast(*maxDisplayFrames)); for (size_t i = 0; i < *maxDisplayFrames; i++) { auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -334,7 +331,7 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); - mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11); + mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence); @@ -355,7 +352,7 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); - mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11); + mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence); @@ -386,9 +383,6 @@ TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceBeforeQueue) { } TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)) - .Times(static_cast(*maxDisplayFrames + 10)); auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); presentFence->signalForTest(2); @@ -398,7 +392,7 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); - mFrameTimeline->setSfWakeUp(sfToken, 22, 11); + mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); mFrameTimeline->setSfPresent(27, presentFence); @@ -408,16 +402,13 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { // Increase the size to 256 mFrameTimeline->setMaxDisplayFrames(256); EXPECT_EQ(*maxDisplayFrames, 256u); - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)) - .Times(static_cast(*maxDisplayFrames + 10)); for (size_t i = 0; i < *maxDisplayFrames + 10; i++) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); - mFrameTimeline->setSfWakeUp(sfToken, 22, 11); + mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); mFrameTimeline->setSfPresent(27, presentFence); @@ -427,16 +418,13 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { // Shrink the size to 128 mFrameTimeline->setMaxDisplayFrames(128); EXPECT_EQ(*maxDisplayFrames, 128u); - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)) - .Times(static_cast(*maxDisplayFrames + 10)); for (size_t i = 0; i < *maxDisplayFrames + 10; i++) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); - mFrameTimeline->setSfWakeUp(sfToken, 22, 11); + mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); mFrameTimeline->setSfPresent(27, presentFence); @@ -447,10 +435,8 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { // Tests related to TimeStats TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { EXPECT_CALL(*mTimeStats, - incrementJankyFrames(sUidOne, sLayerNameOne, + incrementJankyFrames(testing::_, testing::_, sUidOne, sLayerNameOne, HasBit(JankType::SurfaceFlingerCpuDeadlineMissed))); - EXPECT_CALL(*mTimeStats, - incrementJankyFrames(HasBit(JankType::SurfaceFlingerCpuDeadlineMissed))); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast(10ms).count(), @@ -465,7 +451,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast(52ms).count(), - 11); + Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest( @@ -477,8 +463,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { EXPECT_CALL(*mTimeStats, - incrementJankyFrames(sUidOne, sLayerNameOne, HasBit(JankType::DisplayHAL))); - EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::DisplayHAL))); + incrementJankyFrames(testing::_, testing::_, sUidOne, sLayerNameOne, + HasBit(JankType::DisplayHAL))); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( @@ -494,7 +480,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast(52ms).count(), - 30); + Fps::fromPeriodNsecs(30)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest( @@ -506,9 +492,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { EXPECT_CALL(*mTimeStats, - incrementJankyFrames(sUidOne, sLayerNameOne, + incrementJankyFrames(testing::_, testing::_, sUidOne, sLayerNameOne, HasBit(JankType::AppDeadlineMissed))); - EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::AppDeadlineMissed))); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast(10ms).count(), @@ -525,7 +510,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { std::chrono::duration_cast(45ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast(52ms).count(), - 11); + Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -547,8 +532,6 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { */ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { auto tracingSession = getTracingSessionForTest(); - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -559,7 +542,7 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { sLayerNameOne, sLayerNameOne); // Set up the display frame - mFrameTimeline->setSfWakeUp(token1, 20, 11); + mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(25, presentFence1); @@ -567,7 +550,7 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the // next frame - mFrameTimeline->setSfWakeUp(token2, 50, 11); + mFrameTimeline->setSfWakeUp(token2, 50, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(55, presentFence2); auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); @@ -576,10 +559,9 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { TEST_F(FrameTimelineTest, tracing_sanityTest) { auto tracingSession = getTracingSessionForTest(); - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); // Layer specific increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)); + EXPECT_CALL(*mTimeStats, + incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_)); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -591,7 +573,7 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { sLayerNameOne, sLayerNameOne); // Set up the display frame - mFrameTimeline->setSfWakeUp(token2, 20, 11); + mFrameTimeline->setSfWakeUp(token2, 20, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(25, presentFence1); @@ -599,7 +581,7 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the // next frame - mFrameTimeline->setSfWakeUp(token2, 50, 11); + mFrameTimeline->setSfWakeUp(token2, 50, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(55, presentFence2); presentFence2->signalForTest(55); @@ -613,8 +595,6 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) { auto tracingSession = getTracingSessionForTest(); - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -622,13 +602,13 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); // Set up the display frame - mFrameTimeline->setSfWakeUp(-1, 20, 11); + mFrameTimeline->setSfWakeUp(-1, 20, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(25, presentFence1); presentFence1->signalForTest(30); // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the // next frame - mFrameTimeline->setSfWakeUp(token1, 50, 11); + mFrameTimeline->setSfWakeUp(token1, 50, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(55, presentFence2); presentFence2->signalForTest(60); @@ -641,8 +621,6 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) { auto tracingSession = getTracingSessionForTest(); - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -653,7 +631,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) sLayerNameOne, sLayerNameOne); // Set up the display frame - mFrameTimeline->setSfWakeUp(token1, 20, 11); + mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(25, presentFence1); @@ -661,7 +639,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the // next frame - mFrameTimeline->setSfWakeUp(token2, 50, 11); + mFrameTimeline->setSfWakeUp(token2, 50, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(55, presentFence2); presentFence2->signalForTest(60); @@ -759,8 +737,6 @@ void validateTraceEvent(const ProtoFrameEnd& received, const ProtoFrameEnd& sour TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { auto tracingSession = getTracingSessionForTest(); - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -769,7 +745,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); // Set up the display frame - mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, 11); + mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(26, presentFence1); presentFence1->signalForTest(31); @@ -797,7 +773,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the // next frame - mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, 11); + mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(55, presentFence2); presentFence2->signalForTest(55); @@ -854,10 +830,9 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { auto tracingSession = getTracingSessionForTest(); - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); // Layer specific increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)); + EXPECT_CALL(*mTimeStats, + incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_)); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -902,7 +877,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { protoActualSurfaceFrameEnd.set_cookie(traceCookie + 2); // Set up the display frame - mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, 11); + mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(26, presentFence1); @@ -910,7 +885,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { // Trigger a flushPresentFence (which will call trace function) by calling setSfPresent for the // next frame - mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, 11); + mFrameTimeline->setSfWakeUp(displayFrameToken2, 50, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(55, presentFence2); presentFence2->signalForTest(55); @@ -967,17 +942,16 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { // Tests for Jank classification TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) { - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); // Layer specific increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)); + EXPECT_CALL(*mTimeStats, + incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_)); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30}); auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); - mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); + mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); mFrameTimeline->setSfPresent(26, presentFence1); @@ -1001,12 +975,10 @@ TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) { } TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresent) { - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70}); - mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); + mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(26, presentFence1); auto displayFrame = getDisplayFrame(0); presentFence1->signalForTest(30); @@ -1016,7 +988,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresen // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); - mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); + mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(56, presentFence2); displayFrame = getDisplayFrame(0); @@ -1042,12 +1014,10 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresen } TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent) { - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70}); - mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); + mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(26, presentFence1); auto displayFrame = getDisplayFrame(0); presentFence1->signalForTest(50); @@ -1057,7 +1027,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); - mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); + mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(56, presentFence2); displayFrame = getDisplayFrame(0); @@ -1083,11 +1053,9 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent } TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishEarlyPresent) { - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({12, 18, 40}); - mFrameTimeline->setSfWakeUp(sfToken1, 12, 11); + mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(22, presentFence1); auto displayFrame = getDisplayFrame(0); @@ -1107,11 +1075,9 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishEarlyPresent) } TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) { - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40}); - mFrameTimeline->setSfWakeUp(sfToken1, 12, 11); + mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11)); mFrameTimeline->setSfPresent(36, presentFence1); auto displayFrame = getDisplayFrame(0); presentFence1->signalForTest(52); @@ -1130,10 +1096,9 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) } TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresent) { - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2); - // Layer specific increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2); + EXPECT_CALL(*mTimeStats, + incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_)) + .Times(2); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70}); @@ -1143,7 +1108,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(16); - mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); + mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(26, presentFence1); @@ -1162,7 +1127,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(36); - mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); + mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); mFrameTimeline->setSfPresent(56, presentFence2); @@ -1203,10 +1168,9 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen } TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent) { - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2); - // Layer specific increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2); + EXPECT_CALL(*mTimeStats, + incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_)) + .Times(2); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70}); @@ -1216,7 +1180,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(16); - mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); + mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(26, presentFence1); @@ -1235,7 +1199,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(36); - mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); + mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); mFrameTimeline->setSfPresent(56, presentFence2); @@ -1276,10 +1240,9 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent } TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) { - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); - // Layer specific increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)); + EXPECT_CALL(*mTimeStats, + incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_)); + auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 46, 50}); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60}); @@ -1287,7 +1250,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(40); - mFrameTimeline->setSfWakeUp(sfToken1, 42, 11); + mFrameTimeline->setSfWakeUp(sfToken1, 42, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(46, presentFence1); @@ -1320,10 +1283,9 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) // AppDeadlineMissed. Second frame - DisplayFrame is janky. This should propagate DisplayFrame's // jank to the SurfaceFrame. - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2); - // Layer specific increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2); + EXPECT_CALL(*mTimeStats, + incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_)) + .Times(2); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({32, 36, 40}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({42, 46, 50}); @@ -1333,7 +1295,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(26); - mFrameTimeline->setSfWakeUp(sfToken1, 32, 11); + mFrameTimeline->setSfWakeUp(sfToken1, 32, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(36, presentFence1); @@ -1352,7 +1314,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(40); - mFrameTimeline->setSfWakeUp(sfToken2, 43, 11); + mFrameTimeline->setSfWakeUp(sfToken2, 43, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); mFrameTimeline->setSfPresent(56, presentFence2); @@ -1393,10 +1355,10 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) } TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadlineMissed) { - // Global increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)).Times(2); // Layer specific increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_, testing::_, testing::_)).Times(2); + EXPECT_CALL(*mTimeStats, + incrementJankyFrames(testing::_, testing::_, testing::_, testing::_, testing::_)) + .Times(2); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); @@ -1407,7 +1369,7 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(50); - mFrameTimeline->setSfWakeUp(sfToken1, 52, 30); + mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(56, presentFence1); @@ -1426,7 +1388,7 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(84); - mFrameTimeline->setSfWakeUp(sfToken2, 112, 30); + mFrameTimeline->setSfWakeUp(sfToken2, 112, Fps::fromPeriodNsecs(30)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54); mFrameTimeline->addSurfaceFrame(surfaceFrame2); mFrameTimeline->setSfPresent(116, presentFence2); diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index df4464ef52..303b4ebf6e 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -55,14 +55,21 @@ using testing::UnorderedElementsAre; using PowerMode = hardware::graphics::composer::V2_4::IComposerClient::PowerMode; // clang-format off -#define FMT_PROTO true -#define FMT_STRING false -#define LAYER_ID_0 0 -#define LAYER_ID_1 1 -#define UID_0 123 -#define LAYER_ID_INVALID -1 -#define NUM_LAYERS 1 -#define NUM_LAYERS_INVALID "INVALID" +#define FMT_PROTO true +#define FMT_STRING false +#define LAYER_ID_0 0 +#define LAYER_ID_1 1 +#define UID_0 123 +#define REFRESH_RATE_0 61 +#define RENDER_RATE_0 31 +#define REFRESH_RATE_BUCKET_0 60 +#define RENDER_RATE_BUCKET_0 30 +#define LAYER_ID_INVALID -1 +#define NUM_LAYERS 1 +#define NUM_LAYERS_INVALID "INVALID" + +const constexpr Fps kRefreshRate0 = Fps(static_cast(REFRESH_RATE_0)); +const constexpr Fps kRenderRate0 = Fps(static_cast(RENDER_RATE_0)); enum InputCommand : int32_t { ENABLE = 0, @@ -246,11 +253,13 @@ void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumbe ASSERT_NO_FATAL_FAILURE(mTimeStats->setDesiredTime(id, frameNumber, ts)); break; case TimeStamp::PRESENT: - ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentTime(id, frameNumber, ts)); + ASSERT_NO_FATAL_FAILURE( + mTimeStats->setPresentTime(id, frameNumber, ts, kRefreshRate0, kRenderRate0)); break; case TimeStamp::PRESENT_FENCE: - ASSERT_NO_FATAL_FAILURE( - mTimeStats->setPresentFence(id, frameNumber, std::make_shared(ts))); + ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentFence(id, frameNumber, + std::make_shared(ts), + kRefreshRate0, kRenderRate0)); break; default: ALOGD("Invalid timestamp type"); @@ -352,48 +361,29 @@ TEST_F(TimeStatsTest, canIncreaseBadDesiredPresent) { EXPECT_THAT(result, HasSubstr(expectedResult)); } -TEST_F(TimeStatsTest, canIncreaseJankyFrames) { - // this stat is not in the proto so verify by checking the string dump - EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); - mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerCpuDeadlineMissed); - mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed); - mTimeStats->incrementJankyFrames(JankType::DisplayHAL); - mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed); - mTimeStats->incrementJankyFrames(JankType::None); - - const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING)); - std::string expectedResult = "totalTimelineFrames = " + std::to_string(5); - EXPECT_THAT(result, HasSubstr(expectedResult)); - expectedResult = "jankyFrames = " + std::to_string(4); - EXPECT_THAT(result, HasSubstr(expectedResult)); - expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1); - EXPECT_THAT(result, HasSubstr(expectedResult)); - expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1); - EXPECT_THAT(result, HasSubstr(expectedResult)); - expectedResult = "sfUnattributedJankyFrame = " + std::to_string(1); - EXPECT_THAT(result, HasSubstr(expectedResult)); - expectedResult = "appUnattributedJankyFrame = " + std::to_string(1); - EXPECT_THAT(result, HasSubstr(expectedResult)); -} - TEST_F(TimeStatsTest, canIncreaseJankyFramesForLayer) { // this stat is not in the proto so verify by checking the string dump EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), JankType::SurfaceFlingerCpuDeadlineMissed); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), JankType::SurfaceFlingerGpuDeadlineMissed); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + JankType::DisplayHAL); + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), JankType::AppDeadlineMissed); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None); + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + JankType::None); const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING)); - std::string expectedResult = "totalTimelineFrames = " + std::to_string(5); + std::string expectedResult = + "displayRefreshRate = " + std::to_string(REFRESH_RATE_BUCKET_0) + " fps"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "renderRate = " + std::to_string(RENDER_RATE_BUCKET_0) + " fps"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "totalTimelineFrames = " + std::to_string(5); EXPECT_THAT(result, HasSubstr(expectedResult)); expectedResult = "jankyFrames = " + std::to_string(4); EXPECT_THAT(result, HasSubstr(expectedResult)); @@ -848,14 +838,16 @@ TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) { mTimeStats->setPresentFenceGlobal(std::make_shared( std::chrono::duration_cast(1ms).count())); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), JankType::SurfaceFlingerCpuDeadlineMissed); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), JankType::SurfaceFlingerGpuDeadlineMissed); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + JankType::DisplayHAL); + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), JankType::AppDeadlineMissed); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None); + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + JankType::None); EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty()); @@ -865,11 +857,6 @@ TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) { EXPECT_THAT(result, HasSubstr("compositionStrategyChanges = 0")); EXPECT_THAT(result, HasSubstr("averageFrameDuration = 0.000 ms")); EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 0.000 ms")); - EXPECT_THAT(result, HasSubstr("jankyFrames = 0")); - EXPECT_THAT(result, HasSubstr("sfLongCpuJankyFrames = 0")); - EXPECT_THAT(result, HasSubstr("sfLongGpuJankyFrames = 0")); - EXPECT_THAT(result, HasSubstr("sfUnattributedJankyFrame = 0")); - EXPECT_THAT(result, HasSubstr("appUnattributedJankyFrame = 0")); } TEST_F(TimeStatsTest, canDumpWithMaxLayers) { @@ -1000,11 +987,16 @@ TEST_F(TimeStatsTest, globalStatsCallback) { mTimeStats->setPresentFenceGlobal(std::make_shared(3000000)); mTimeStats->setPresentFenceGlobal(std::make_shared(5000000)); - mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerCpuDeadlineMissed); - mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed); - mTimeStats->incrementJankyFrames(JankType::DisplayHAL); - mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed); - mTimeStats->incrementJankyFrames(JankType::None); + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + JankType::SurfaceFlingerCpuDeadlineMissed); + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + JankType::SurfaceFlingerGpuDeadlineMissed); + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + JankType::DisplayHAL); + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + JankType::AppDeadlineMissed); + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + JankType::None); EXPECT_THAT(mDelegate->mAtomTags, UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, @@ -1047,7 +1039,7 @@ TEST_F(TimeStatsTest, globalStatsCallback) { EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0)); EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0)); EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0)); + EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0)); EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, BytesEq((const uint8_t*)expectedEmptyHistogram.c_str(), @@ -1058,7 +1050,7 @@ TEST_F(TimeStatsTest, globalStatsCallback) { BytesEq((const uint8_t*)expectedEmptyHistogram.c_str(), expectedEmptyHistogram.size()), expectedEmptyHistogram.size())); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0)); + EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0)); EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent)); } @@ -1091,14 +1083,16 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { } insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), JankType::SurfaceFlingerCpuDeadlineMissed); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), JankType::SurfaceFlingerGpuDeadlineMissed); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::DisplayHAL); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + JankType::DisplayHAL); + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), JankType::AppDeadlineMissed); - mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None); + mTimeStats->incrementJankyFrames(kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + JankType::None); EXPECT_THAT(mDelegate->mAtomTags, UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, @@ -1170,8 +1164,8 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0)); EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0)); EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0)); - EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, 0)); + EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, REFRESH_RATE_BUCKET_0)); + EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, RENDER_RATE_BUCKET_0)); EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, BytesEq((const uint8_t*) diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h index 0a6a9f4550..44b9b73fd4 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h +++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h @@ -31,7 +31,7 @@ public: MOCK_METHOD0(onBootFinished, void()); MOCK_METHOD1(addSurfaceFrame, void(std::shared_ptr)); - MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, nsecs_t)); + MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, Fps)); MOCK_METHOD2(setSfPresent, void(nsecs_t, const std::shared_ptr&)); }; diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h index 99ec353095..ebea5a01d4 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h @@ -48,10 +48,12 @@ public: MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t)); MOCK_METHOD3(setAcquireTime, void(int32_t, uint64_t, nsecs_t)); MOCK_METHOD3(setAcquireFence, void(int32_t, uint64_t, const std::shared_ptr&)); - MOCK_METHOD3(setPresentTime, void(int32_t, uint64_t, nsecs_t)); - MOCK_METHOD3(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr&)); - MOCK_METHOD1(incrementJankyFrames, void(int32_t)); - MOCK_METHOD3(incrementJankyFrames, void(uid_t, const std::string&, int32_t)); + MOCK_METHOD5(setPresentTime, void(int32_t, uint64_t, nsecs_t, Fps, std::optional)); + MOCK_METHOD5(setPresentFence, + void(int32_t, uint64_t, const std::shared_ptr&, Fps, + std::optional)); + MOCK_METHOD5(incrementJankyFrames, + void(Fps, std::optional, uid_t, const std::string&, int32_t)); MOCK_METHOD1(onDestroy, void(int32_t)); MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t)); MOCK_METHOD1(setPowerMode, -- cgit v1.2.3-59-g8ed1b From a7cda15da4b51387c322e45bc4c28122642836d3 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Fri, 26 Feb 2021 17:49:41 -0800 Subject: SurfaceFlinger: Check frameIsEarly earlier If we allow the transaction to apply but then later delay the buffer we may end up 'splitting a transaction' applying part of it without applying an included buffer. Bug: 179712630 Test: Existing tests pass Change-Id: Ia54ba0f9b34a7b676af95418181c2e0f0b807b25 --- services/surfaceflinger/BufferLayer.cpp | 6 ------ services/surfaceflinger/Layer.h | 2 ++ services/surfaceflinger/SurfaceFlinger.cpp | 4 ++++ 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 097f7de891..a96dffdcb7 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -414,12 +414,6 @@ bool BufferLayer::shouldPresentNow(nsecs_t expectedPresentTime) const { return true; } - // If the next planned present time is not current, return and try again later - if (frameIsEarly(expectedPresentTime)) { - ATRACE_NAME("frameIsEarly()"); - return false; - } - // If this layer doesn't have a frame is shouldn't be presented if (!hasFrameUpdate()) { return false; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 23758c930c..a072554e2b 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -924,6 +924,8 @@ public: pid_t getOwnerPid() { return mOwnerPid; } + virtual bool frameIsEarly(nsecs_t /*expectedPresentTime*/) const { return false; } + // This layer is not a clone, but it's the parent to the cloned hierarchy. The // variable mClonedChild represents the top layer that will be cloned so this // layer will be the parent of mClonedChild. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5364adfa45..fdefca77d1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3361,6 +3361,10 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( if (!layer) { continue; } + if (layer->frameIsEarly(expectedPresentTime)) { + ATRACE_NAME("frameIsEarly()"); + return false; + } if (!mScheduler->isVsyncValid(expectedPresentTime, layer->getOwnerUid())) { ATRACE_NAME("!isVsyncValidForUid"); -- cgit v1.2.3-59-g8ed1b From 43752eba5a28f2b923cded40b3d6e6d1db968a08 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 4 Mar 2021 16:24:25 -0800 Subject: SurfaceFlinger: get nextPredictedPresentTime directly from frame timeline ag/13715677 moved the call to check whether a frame is early or not before a transaction is applied. This created a bug in BufferStateLayer::nextPredictedPresentTime since it is checking the drawing state surface frame, which is not valid since the transaction is not applied yet. This CL is fixing this by pasing the vsync id itself, and getting the expected present time base on that vsync id. Change-Id: I0f95f2a3a2efff921964a6fb5f9b50e0fcc65a85 Test: launch an app and observe systraces Bug: 181978893 --- services/surfaceflinger/BufferLayer.cpp | 4 ++-- services/surfaceflinger/BufferLayer.h | 4 ++-- services/surfaceflinger/BufferQueueLayer.cpp | 2 +- services/surfaceflinger/BufferQueueLayer.h | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 9 +++++---- services/surfaceflinger/BufferStateLayer.h | 2 +- services/surfaceflinger/Layer.h | 4 +++- services/surfaceflinger/SurfaceFlinger.cpp | 25 +++++++++++++++---------- services/surfaceflinger/SurfaceFlinger.h | 3 ++- 9 files changed, 32 insertions(+), 23 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index a96dffdcb7..eac3d95d8a 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -424,12 +424,12 @@ bool BufferLayer::shouldPresentNow(nsecs_t expectedPresentTime) const { return isBufferDue(expectedPresentTime); } -bool BufferLayer::frameIsEarly(nsecs_t expectedPresentTime) const { +bool BufferLayer::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const { // TODO(b/169901895): kEarlyLatchVsyncThreshold should be based on the // vsync period. We can do this change as soon as ag/13100772 is merged. constexpr static std::chrono::nanoseconds kEarlyLatchVsyncThreshold = 5ms; - const auto presentTime = nextPredictedPresentTime(); + const auto presentTime = nextPredictedPresentTime(vsyncId); if (!presentTime.has_value()) { return false; } diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 2118f4ad18..d215298eda 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -191,7 +191,7 @@ protected: // Returns true if the next frame is considered too early to present // at the given expectedPresentTime - bool frameIsEarly(nsecs_t expectedPresentTime) const; + bool frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const; std::atomic mAutoRefresh{false}; std::atomic mSidebandStreamChanged{false}; @@ -238,7 +238,7 @@ private: FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; // Returns the predicted present time of the next frame if available - virtual std::optional nextPredictedPresentTime() const = 0; + virtual std::optional nextPredictedPresentTime(int64_t vsyncId) const = 0; // The amount of time SF can delay a frame if it is considered early based // on the VsyncModulator::VsyncConfig::appWorkDuration diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 3615a0209f..63dd25f72f 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -215,7 +215,7 @@ bool BufferQueueLayer::hasFrameUpdate() const { return mQueuedFrames > 0; } -std::optional BufferQueueLayer::nextPredictedPresentTime() const { +std::optional BufferQueueLayer::nextPredictedPresentTime(int64_t /*vsyncId*/) const { Mutex::Autolock lock(mQueueItemLock); if (mQueueItems.empty()) { return std::nullopt; diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 0ea02e19a7..3a34b952f2 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -117,7 +117,7 @@ private: // Temporary - Used only for LEGACY camera mode. uint32_t getProducerStickyTransform() const; - std::optional nextPredictedPresentTime() const override; + std::optional nextPredictedPresentTime(int64_t vsyncId) const override; sp mConsumer; sp mProducer; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 296085a0b5..58221e71ab 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -605,13 +605,14 @@ bool BufferStateLayer::hasFrameUpdate() const { return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr); } -std::optional BufferStateLayer::nextPredictedPresentTime() const { - const State& drawingState(getDrawingState()); - if (!drawingState.isAutoTimestamp || !drawingState.bufferSurfaceFrameTX) { +std::optional BufferStateLayer::nextPredictedPresentTime(int64_t vsyncId) const { + const auto prediction = + mFlinger->mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId); + if (!prediction.has_value()) { return std::nullopt; } - return drawingState.bufferSurfaceFrameTX->getPredictions().presentTime; + return prediction->presentTime; } status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime, diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 6b422ea204..db0ebfc479 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -156,7 +156,7 @@ private: bool bufferNeedsFiltering() const override; - std::optional nextPredictedPresentTime() const override; + std::optional nextPredictedPresentTime(int64_t vsyncId) const override; static const std::array IDENTITY_MATRIX; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index ce97155eaa..34a9f39b6d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -922,7 +922,9 @@ public: pid_t getOwnerPid() { return mOwnerPid; } - virtual bool frameIsEarly(nsecs_t /*expectedPresentTime*/) const { return false; } + virtual bool frameIsEarly(nsecs_t /*expectedPresentTime*/, int64_t /*vsyncId*/) const { + return false; + } // This layer is not a clone, but it's the parent to the cloned hierarchy. The // variable mClonedChild represents the top layer that will be cloned so this diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ad91183f18..e27b8dd01a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3315,10 +3315,10 @@ void SurfaceFlinger::flushTransactionQueues() { while (!transactionQueue.empty()) { const auto& transaction = transactionQueue.front(); - if (!transactionIsReadyToBeApplied(transaction.isAutoTimestamp, + if (!transactionIsReadyToBeApplied(transaction.frameTimelineInfo, + transaction.isAutoTimestamp, transaction.desiredPresentTime, - transaction.states, - pendingBuffers)) { + transaction.states, pendingBuffers)) { setTransactionFlags(eTransactionFlushNeeded); break; } @@ -3342,10 +3342,10 @@ void SurfaceFlinger::flushTransactionQueues() { const auto& transaction = mTransactionQueue.front(); bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) != mPendingTransactionQueues.end(); - if (!transactionIsReadyToBeApplied(transaction.isAutoTimestamp, + if (!transactionIsReadyToBeApplied(transaction.frameTimelineInfo, + transaction.isAutoTimestamp, transaction.desiredPresentTime, - transaction.states, - pendingBuffers) || + transaction.states, pendingBuffers) || pendingTransactions) { mPendingTransactionQueues[transaction.applyToken].push(transaction); } else { @@ -3375,7 +3375,8 @@ bool SurfaceFlinger::transactionFlushNeeded() { } bool SurfaceFlinger::transactionIsReadyToBeApplied( - bool isAutoTimestamp, int64_t desiredPresentTime, const Vector& states, + const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, + const Vector& states, std::unordered_set, ISurfaceComposer::SpHash>& pendingBuffers) { const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); bool ready = true; @@ -3391,6 +3392,7 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( if (!(s.what & layer_state_t::eAcquireFenceChanged)) { continue; } + if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) { ready = false; } @@ -3405,7 +3407,10 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( if (!layer) { continue; } - if (layer->frameIsEarly(expectedPresentTime)) { + + const bool frameTimelineInfoChanged = (s.what & layer_state_t::eFrameTimelineInfoChanged); + const auto vsyncId = frameTimelineInfoChanged ? s.frameTimelineInfo.vsyncId : info.vsyncId; + if (isAutoTimestamp && layer->frameIsEarly(expectedPresentTime, vsyncId)) { ATRACE_NAME("frameIsEarly()"); return false; } @@ -3415,8 +3420,8 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( ready = false; } - // If backpressure is enabled and we already have a buffer to commit, keep the transaction - // in the queue. + // If backpressure is enabled and we already have a buffer to commit, keep the + // transaction in the queue. const bool hasPendingBuffer = pendingBuffers.find(s.surface) != pendingBuffers.end(); if (layer->backpressureEnabled() && hasPendingBuffer && isAutoTimestamp) { ready = false; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6434ca29ff..6d3b4efa84 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -800,7 +800,8 @@ private: void commitTransaction() REQUIRES(mStateLock); void commitOffscreenLayers(); bool transactionIsReadyToBeApplied( - bool isAutoTimestamp, int64_t desiredPresentTime, const Vector& states, + const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, + const Vector& states, std::unordered_set, ISurfaceComposer::SpHash>& pendingBuffers) REQUIRES(mStateLock); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); -- cgit v1.2.3-59-g8ed1b From 8db101095526c49a58fd54bfb9d3501ea5351027 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 15 Mar 2021 17:19:23 -0700 Subject: SurfaceFlinger: remove SurfaceControl level vsyncId setting FrameTimelineInfo can be set on the entire transaction, or for an individual SurfaceControl. Later in the code the FrameTimelineInfo is unified based on the most recent vsyncId. For this reason we are removing the setting of a FrameTimelineInfo on a SurfaceControl and instead we use the transaction's one. Test: adb shell /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test Bug: 181978893 Bug: 169901895 Change-Id: Id4a8e46d57fbda66f6d478be82313482053dce20 --- libs/gui/BLASTBufferQueue.cpp | 2 +- libs/gui/LayerState.cpp | 7 ---- libs/gui/SurfaceComposerClient.cpp | 15 +------ libs/gui/include/gui/LayerState.h | 9 ++--- libs/gui/include/gui/SurfaceComposerClient.h | 3 -- services/surfaceflinger/BufferLayer.cpp | 18 --------- services/surfaceflinger/BufferLayer.h | 11 ------ services/surfaceflinger/BufferQueueLayer.cpp | 15 ------- services/surfaceflinger/BufferQueueLayer.h | 2 - services/surfaceflinger/BufferStateLayer.cpp | 10 ----- services/surfaceflinger/BufferStateLayer.h | 2 - services/surfaceflinger/Layer.h | 4 -- services/surfaceflinger/SurfaceFlinger.cpp | 48 +++++++++++++++-------- services/surfaceflinger/SurfaceFlinger.h | 1 + services/surfaceflinger/tests/LayerState_test.cpp | 29 -------------- 15 files changed, 38 insertions(+), 138 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index f778232803..5b1b975283 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -401,7 +401,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber); if (!mNextFrameTimelineInfoQueue.empty()) { - t->setFrameTimelineInfo(mSurfaceControl, mNextFrameTimelineInfoQueue.front()); + t->setFrameTimelineInfo(mNextFrameTimelineInfoQueue.front()); mNextFrameTimelineInfoQueue.pop(); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 7a18ca61fe..a84e741482 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -62,7 +62,6 @@ layer_state_t::layer_state_t() shouldBeSeamless(true), fixedTransformHint(ui::Transform::ROT_INVALID), frameNumber(0), - frameTimelineInfo(), autoRefresh(false), releaseBufferListener(nullptr) { matrix.dsdx = matrix.dtdy = 1.0f; @@ -151,7 +150,6 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeBool, shouldBeSeamless); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeUint64, frameNumber); - SAFE_PARCEL(frameTimelineInfo.write, output); SAFE_PARCEL(output.writeBool, autoRefresh); SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(releaseBufferListener)); @@ -274,7 +272,6 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readUint64, &frameNumber); - SAFE_PARCEL(frameTimelineInfo.read, input); SAFE_PARCEL(input.readBool, &autoRefresh); tmpBinder = nullptr; @@ -543,10 +540,6 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFrameNumberChanged; frameNumber = other.frameNumber; } - if (other.what & eFrameTimelineInfoChanged) { - what |= eFrameTimelineInfoChanged; - frameTimelineInfo.merge(other.frameTimelineInfo); - } if (other.what & eAutoRefreshChanged) { what |= eAutoRefreshChanged; autoRefresh = other.autoRefresh; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 11fe49039d..eaccc5bab5 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1630,20 +1630,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixed SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( const FrameTimelineInfo& frameTimelineInfo) { - mFrameTimelineInfo = frameTimelineInfo; - return *this; -} - -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( - const sp& sc, const FrameTimelineInfo& frameTimelineInfo) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - - s->what |= layer_state_t::eFrameTimelineInfoChanged; - s->frameTimelineInfo = frameTimelineInfo; + mFrameTimelineInfo.merge(frameTimelineInfo); return *this; } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index d68a9cfa4a..4a52168315 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -133,10 +133,9 @@ struct layer_state_t { eProducerDisconnect = 0x100'00000000, eFixedTransformHintChanged = 0x200'00000000, eFrameNumberChanged = 0x400'00000000, - eFrameTimelineInfoChanged = 0x800'00000000, - eBlurRegionsChanged = 0x1000'00000000, - eAutoRefreshChanged = 0x2000'00000000, - eStretchChanged = 0x4000'00000000, + eBlurRegionsChanged = 0x800'00000000, + eAutoRefreshChanged = 0x1000'00000000, + eStretchChanged = 0x2000'00000000, }; layer_state_t(); @@ -239,8 +238,6 @@ struct layer_state_t { // graphics producer. uint64_t frameNumber; - FrameTimelineInfo frameTimelineInfo; - // Indicates that the consumer should acquire the next frame as soon as it // can and not wait for a frame to become available. This is only relevant // in shared buffer mode. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index f29983cef7..ae7170e1aa 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -530,9 +530,6 @@ public: // to the transaction, and the input event id that identifies the input event that caused // the current frame. Transaction& setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo); - // Variant that only applies to a specific SurfaceControl. - Transaction& setFrameTimelineInfo(const sp& sc, - const FrameTimelineInfo& frameTimelineInfo); // Indicates that the consumer should acquire the next frame as soon as it // can and not wait for a frame to become available. This is only relevant diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index eac3d95d8a..b3f97924bd 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -424,24 +424,6 @@ bool BufferLayer::shouldPresentNow(nsecs_t expectedPresentTime) const { return isBufferDue(expectedPresentTime); } -bool BufferLayer::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const { - // TODO(b/169901895): kEarlyLatchVsyncThreshold should be based on the - // vsync period. We can do this change as soon as ag/13100772 is merged. - constexpr static std::chrono::nanoseconds kEarlyLatchVsyncThreshold = 5ms; - - const auto presentTime = nextPredictedPresentTime(vsyncId); - if (!presentTime.has_value()) { - return false; - } - - if (std::abs(*presentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold.count()) { - return false; - } - - return *presentTime >= expectedPresentTime && - *presentTime - expectedPresentTime >= kEarlyLatchVsyncThreshold.count(); -} - bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) { ATRACE_CALL(); diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 5fed79ffed..b8d3f12322 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -189,10 +189,6 @@ protected: // specific logic virtual bool isBufferDue(nsecs_t /*expectedPresentTime*/) const = 0; - // Returns true if the next frame is considered too early to present - // at the given expectedPresentTime - bool frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const; - std::atomic mAutoRefresh{false}; std::atomic mSidebandStreamChanged{false}; @@ -236,13 +232,6 @@ private: std::unique_ptr mCompositionState; FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; - - // Returns the predicted present time of the next frame if available - virtual std::optional nextPredictedPresentTime(int64_t vsyncId) const = 0; - - // The amount of time SF can delay a frame if it is considered early based - // on the VsyncModulator::VsyncConfig::appWorkDuration - static constexpr std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms; }; } // namespace android diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 63dd25f72f..51e85c4dcc 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -215,21 +215,6 @@ bool BufferQueueLayer::hasFrameUpdate() const { return mQueuedFrames > 0; } -std::optional BufferQueueLayer::nextPredictedPresentTime(int64_t /*vsyncId*/) const { - Mutex::Autolock lock(mQueueItemLock); - if (mQueueItems.empty()) { - return std::nullopt; - } - - const auto& bufferData = mQueueItems[0]; - - if (!bufferData.item.mIsAutoTimestamp || !bufferData.surfaceFrame) { - return std::nullopt; - } - - return bufferData.surfaceFrame->getPredictions().presentTime; -} - status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) { // This boolean is used to make sure that SurfaceFlinger's shadow copy diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 3a34b952f2..b3b7948935 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -117,8 +117,6 @@ private: // Temporary - Used only for LEGACY camera mode. uint32_t getProducerStickyTransform() const; - std::optional nextPredictedPresentTime(int64_t vsyncId) const override; - sp mConsumer; sp mProducer; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 89dfb6fb6b..00a6d661c0 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -644,16 +644,6 @@ bool BufferStateLayer::hasFrameUpdate() const { return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr); } -std::optional BufferStateLayer::nextPredictedPresentTime(int64_t vsyncId) const { - const auto prediction = - mFlinger->mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId); - if (!prediction.has_value()) { - return std::nullopt; - } - - return prediction->presentTime; -} - status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime, nsecs_t /*expectedPresentTime*/) { const State& s(getDrawingState()); diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 036e8d2e85..7a3da6fec1 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -156,8 +156,6 @@ private: bool bufferNeedsFiltering() const override; - std::optional nextPredictedPresentTime(int64_t vsyncId) const override; - static const std::array IDENTITY_MATRIX; std::unique_ptr mTextureImage; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 85ff479344..1c5d6ecb03 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -930,10 +930,6 @@ public: pid_t getOwnerPid() { return mOwnerPid; } - virtual bool frameIsEarly(nsecs_t /*expectedPresentTime*/, int64_t /*vsyncId*/) const { - return false; - } - // This layer is not a clone, but it's the parent to the cloned hierarchy. The // variable mClonedChild represents the top layer that will be cloned so this // layer will be the parent of mClonedChild. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 61cc8a2ff0..e580a97b90 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3379,6 +3379,28 @@ bool SurfaceFlinger::transactionFlushNeeded() { return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty(); } +bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const { + // The amount of time SF can delay a frame if it is considered early based + // on the VsyncModulator::VsyncConfig::appWorkDuration + constexpr static std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms; + + const auto currentVsyncPeriod = mScheduler->getDisplayStatInfo(systemTime()).vsyncPeriod; + const auto earlyLatchVsyncThreshold = currentVsyncPeriod / 2; + + const auto prediction = mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId); + if (!prediction.has_value()) { + return false; + } + + if (std::abs(prediction->presentTime - expectedPresentTime) >= + kEarlyLatchMaxThreshold.count()) { + return false; + } + + return prediction->presentTime >= expectedPresentTime && + prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold; +} + bool SurfaceFlinger::transactionIsReadyToBeApplied( const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector& states, @@ -3399,6 +3421,13 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( ready = false; } + // If the client didn't specify desiredPresentTime, use the vsyncId to determine the expected + // present time of this transaction. + if (isAutoTimestamp && frameIsEarly(expectedPresentTime, info.vsyncId)) { + ATRACE_NAME("frameIsEarly"); + ready = false; + } + for (const ComposerState& state : states) { const layer_state_t& s = state.state; const bool acquireFenceChanged = (s.what & layer_state_t::eAcquireFenceChanged); @@ -3420,13 +3449,6 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( ATRACE_NAME(layer->getName().c_str()); - const bool frameTimelineInfoChanged = (s.what & layer_state_t::eFrameTimelineInfoChanged); - const auto vsyncId = frameTimelineInfoChanged ? s.frameTimelineInfo.vsyncId : info.vsyncId; - if (isAutoTimestamp && layer->frameIsEarly(expectedPresentTime, vsyncId)) { - ATRACE_NAME("frameIsEarly()"); - ready = false; - } - if (acquireFenceChanged) { // If backpressure is enabled and we already have a buffer to commit, keep the // transaction in the queue. @@ -3959,12 +3981,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } - FrameTimelineInfo info; - if (what & layer_state_t::eFrameTimelineInfoChanged) { - info = s.frameTimelineInfo; - } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { - info = frameTimelineInfo; - } if (what & layer_state_t::eFixedTransformHintChanged) { if (layer->setFixedTransformHint(s.fixedTransformHint)) { flags |= eTraversalNeeded | eTransformHintUpdateNeeded; @@ -4027,12 +4043,12 @@ uint32_t SurfaceFlinger::setClientStateLocked( : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1; if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp, - s.cachedBuffer, frameNumber, dequeueBufferTimestamp, info, + s.cachedBuffer, frameNumber, dequeueBufferTimestamp, frameTimelineInfo, s.releaseBufferListener)) { flags |= eTraversalNeeded; } - } else if (info.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { - layer->setFrameTimelineVsyncForBufferlessTransaction(info, postTime); + } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { + layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime); } if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a5b06dfbd4..a7cdcd1719 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -844,6 +844,7 @@ private: uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock); + bool frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const; /* * Layer management */ diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp index f010786601..fa1a5ed6b0 100644 --- a/services/surfaceflinger/tests/LayerState_test.cpp +++ b/services/surfaceflinger/tests/LayerState_test.cpp @@ -114,34 +114,5 @@ TEST(LayerStateTest, ParcellingScreenCaptureResults) { ASSERT_EQ(results.result, results2.result); } -/** - * Parcel a layer_state_t struct, and then unparcel. Ensure that the object that was parceled - * matches the object that's unparceled. - */ -TEST(LayerStateTest, ParcelUnparcelLayerStateT) { - layer_state_t input; - input.frameTimelineInfo.vsyncId = 1; - input.frameTimelineInfo.inputEventId = 2; - Parcel p; - input.write(p); - layer_state_t output; - p.setDataPosition(0); - output.read(p); - ASSERT_EQ(input.frameTimelineInfo.vsyncId, output.frameTimelineInfo.vsyncId); - ASSERT_EQ(input.frameTimelineInfo.inputEventId, output.frameTimelineInfo.inputEventId); -} - -TEST(LayerStateTest, LayerStateMerge_SelectsValidInputEvent) { - layer_state_t layer1; - layer1.frameTimelineInfo.inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID; - layer_state_t layer2; - layer2.frameTimelineInfo.inputEventId = 1; - layer2.what |= layer_state_t::eFrameTimelineInfoChanged; - - layer1.merge(layer2); - - ASSERT_EQ(1, layer1.frameTimelineInfo.inputEventId); -} - } // namespace test } // namespace android -- cgit v1.2.3-59-g8ed1b From b6a2fa19d91c93f06790507d44fbbaf2484021f8 Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan Date: Sat, 13 Mar 2021 00:23:09 +0000 Subject: Add Gpu composition info to FrameTimeline Post composition, update the Display and SurfaceFrames that were composited by the GPU. Bug: 169876734 Test: None Change-Id: Iad9c6e9714b28a56bfdcc32e514ab180850536b1 --- services/surfaceflinger/BufferLayer.cpp | 7 +++++++ services/surfaceflinger/BufferStateLayer.cpp | 1 - services/surfaceflinger/FrameTimeline/FrameTimeline.cpp | 15 ++++++++++++++- services/surfaceflinger/FrameTimeline/FrameTimeline.h | 16 +++++++++------- services/surfaceflinger/SurfaceFlinger.cpp | 3 ++- .../tests/unittests/mock/MockFrameTimeline.h | 2 +- 6 files changed, 33 insertions(+), 11 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index eac3d95d8a..1ae7533ba3 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -355,6 +355,13 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, clientCompositionTimestamp, FrameTracer::FrameEvent::FALLBACK_COMPOSITION); + // Update the SurfaceFrames in the drawing state + if (mDrawingState.bufferSurfaceFrameTX) { + mDrawingState.bufferSurfaceFrameTX->setGpuComposition(); + } + for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) { + surfaceFrame->setGpuComposition(); + } } std::shared_ptr frameReadyFence = mBufferInfo.mFenceTime; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 96a0c3cd75..0b99623f16 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -664,7 +664,6 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse // are processing the next state. addSurfaceFramePresentedForBuffer(bufferSurfaceFrame, mDrawingState.acquireFence->getSignalTime(), latchTime); - bufferSurfaceFrame.reset(); } mCurrentStateModified = false; diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index b1dff8d11d..2784861b4b 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -348,6 +348,11 @@ void SurfaceFrame::setRenderRate(Fps renderRate) { mRenderRate = renderRate; } +void SurfaceFrame::setGpuComposition() { + std::scoped_lock lock(mMutex); + mGpuComposition = true; +} + std::optional SurfaceFrame::getJankType() const { std::scoped_lock lock(mMutex); if (mPresentState == PresentState::Dropped) { @@ -828,10 +833,14 @@ void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, Fps refreshRa } void FrameTimeline::setSfPresent(nsecs_t sfPresentTime, - const std::shared_ptr& presentFence) { + const std::shared_ptr& presentFence, + bool gpuComposition) { ATRACE_CALL(); std::scoped_lock lock(mMutex); mCurrentDisplayFrame->setActualEndTime(sfPresentTime); + if (gpuComposition) { + mCurrentDisplayFrame->setGpuComposition(); + } mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame)); flushPendingPresentFences(); finalizeCurrentDisplayFrame(); @@ -869,6 +878,10 @@ void FrameTimeline::DisplayFrame::setActualEndTime(nsecs_t actualEndTime) { mSurfaceFlingerActuals.endTime = actualEndTime; } +void FrameTimeline::DisplayFrame::setGpuComposition() { + mGpuComposition = true; +} + void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync) { if (mPredictionState == PredictionState::Expired || mSurfaceFlingerActuals.presentTime == Fence::SIGNAL_TIME_INVALID) { diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index 3cf35f0132..3f04592b6e 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -180,6 +180,7 @@ public: void setDropTime(nsecs_t dropTime); void setPresentState(PresentState presentState, nsecs_t lastLatchTime = 0); void setRenderRate(Fps renderRate); + void setGpuComposition(); // When a bufferless SurfaceFrame is promoted to a buffer SurfaceFrame, we also have to update // isBuffer. @@ -292,11 +293,11 @@ public: // the token and sets the actualSfWakeTime for the current DisplayFrame. virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) = 0; - // Sets the sfPresentTime and finalizes the current DisplayFrame. Tracks the given present fence - // until it's signaled, and updates the present timestamps of all presented SurfaceFrames in - // that vsync. - virtual void setSfPresent(nsecs_t sfPresentTime, - const std::shared_ptr& presentFence) = 0; + // Sets the sfPresentTime, gpuComposition and finalizes the current DisplayFrame. Tracks the + // given present fence until it's signaled, and updates the present timestamps of all presented + // SurfaceFrames in that vsync. + virtual void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr& presentFence, + bool gpuComposition) = 0; // Args: // -jank : Dumps only the Display Frames that are either janky themselves @@ -375,6 +376,7 @@ public: void setPredictions(PredictionState predictionState, TimelineItem predictions); void setActualStartTime(nsecs_t actualStartTime); void setActualEndTime(nsecs_t actualEndTime); + void setGpuComposition(); // BaseTime is the smallest timestamp in a DisplayFrame. // Used for dumping all timestamps relative to the oldest, making it easy to read. @@ -444,8 +446,8 @@ public: int32_t layerId, std::string layerName, std::string debugName, bool isBuffer) override; void addSurfaceFrame(std::shared_ptr surfaceFrame) override; void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override; - void setSfPresent(nsecs_t sfPresentTime, - const std::shared_ptr& presentFence) override; + void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr& presentFence, + bool gpuComposition = false) override; void parseArgs(const Vector& args, std::string& result) override; void setMaxDisplayFrames(uint32_t size) override; float computeFps(const std::unordered_set& layerIds) override; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d048380dd2..184a403e8b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2110,7 +2110,8 @@ void SurfaceFlinger::postComposition() { // information from previous' frame classification is already available when sending jank info // to clients, so they get jank classification as early as possible. mFrameTimeline->setSfPresent(systemTime(), - std::make_shared(mPreviousPresentFences[0])); + std::make_shared(mPreviousPresentFences[0]), + glCompositionDoneFenceTime != FenceTime::NO_FENCE); nsecs_t dequeueReadyTime = systemTime(); for (const auto& layer : mLayersWithQueuedFrames) { diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h index b9d17946b9..570797861d 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h +++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h @@ -32,7 +32,7 @@ public: MOCK_METHOD0(onBootFinished, void()); MOCK_METHOD1(addSurfaceFrame, void(std::shared_ptr)); MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, Fps)); - MOCK_METHOD2(setSfPresent, void(nsecs_t, const std::shared_ptr&)); + MOCK_METHOD3(setSfPresent, void(nsecs_t, const std::shared_ptr&, bool)); MOCK_METHOD1(computeFps, float(const std::unordered_set&)); }; -- cgit v1.2.3-59-g8ed1b From 7a60afbefee3ba58972cb8c4378937a362f9bde9 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 29 Mar 2021 13:20:55 -0700 Subject: SF: black out layers that doesn't have gpu accessible buffer If a layer provided a non gpu readable buffer, and that layer needs to be composited using the gpu, backout the layer instead of asserting in RenderEngine. Fixes: 183950013 Test: launch the apk attached to the bug and force client composition Change-Id: I068d72acf58866150284b3770b7c33da5a3bd3ac --- services/surfaceflinger/BufferLayer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 4ace4c27a0..8f1aef06f2 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -185,10 +185,14 @@ std::optional BufferLayer::prepareCli return std::nullopt; } } - bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || + const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || (isSecure() && !targetSettings.isSecure); + const bool bufferCanBeUsedAsHwTexture = + mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; compositionengine::LayerFE::LayerSettings& layer = *result; - if (blackOutLayer) { + if (blackOutLayer || !bufferCanBeUsedAsHwTexture) { + ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable", + mName.c_str()); prepareClearClientComposition(layer, true /* blackout */); return layer; } -- cgit v1.2.3-59-g8ed1b From 8b9e612e0fd797e7868de435d840eb6d2d756c1b Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 26 Jan 2021 19:11:45 -0800 Subject: SF: Add setFrameRate vote to TimeStats Test: SF unit tests Bug: 172939060 Change-Id: I60ea90c6f31b4bb22f39dea654de14e6c354974c --- services/surfaceflinger/BufferLayer.cpp | 39 +++++- services/surfaceflinger/TimeStats/TimeStats.cpp | 33 +++-- services/surfaceflinger/TimeStats/TimeStats.h | 16 ++- .../TimeStats/timestatsproto/TimeStatsHelper.cpp | 33 +++++ .../include/timestatsproto/TimeStatsHelper.h | 23 ++++ .../tests/unittests/TimeStatsTest.cpp | 136 ++++++++++++++++++--- .../tests/unittests/mock/MockTimeStats.h | 9 +- 7 files changed, 252 insertions(+), 37 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 4ace4c27a0..b6764d02d2 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -325,6 +325,37 @@ bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) { mRefreshPending = false; return hasReadyFrame(); } +namespace { +TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) { + using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility; + using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness; + const auto frameRateCompatibility = [frameRate] { + switch (frameRate.type) { + case Layer::FrameRateCompatibility::Default: + return FrameRateCompatibility::Default; + case Layer::FrameRateCompatibility::ExactOrMultiple: + return FrameRateCompatibility::ExactOrMultiple; + default: + return FrameRateCompatibility::Undefined; + } + }(); + + const auto seamlessness = [frameRate] { + switch (frameRate.seamlessness) { + case scheduler::Seamlessness::OnlySeamless: + return Seamlessness::ShouldBeSeamless; + case scheduler::Seamlessness::SeamedAndSeamless: + return Seamlessness::NotRequired; + default: + return Seamlessness::Undefined; + } + }(); + + return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(), + .frameRateCompatibility = frameRateCompatibility, + .seamlessness = seamlessness}; +} +} // namespace bool BufferLayer::onPostComposition(const DisplayDevice* display, const std::shared_ptr& glDoneFence, @@ -377,7 +408,9 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, const std::optional renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); if (presentFence->isValid()) { mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence, - refreshRate, renderRate); + refreshRate, renderRate, + frameRateToSetFrameRateVotePayload( + mDrawingState.frameRate)); mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, presentFence, FrameTracer::FrameEvent::PRESENT_FENCE); mFrameTracker.setActualPresentFence(std::shared_ptr(presentFence)); @@ -389,7 +422,9 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, // timestamp instead. const nsecs_t actualPresentTime = display->getRefreshTimestamp(); mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime, - refreshRate, renderRate); + refreshRate, renderRate, + frameRateToSetFrameRateVotePayload( + mDrawingState.frameRate)); mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, actualPresentTime, FrameTracer::FrameEvent::PRESENT_FENCE); diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 974ae8484f..2094972ed0 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -89,12 +89,15 @@ std::string histogramToProtoByteString(const std::unordered_map(frameRateCompatibility)); + proto.write(android::util::FIELD_TYPE_ENUM | 3 /* field id */, static_cast(seamlessness)); std::string byteString; proto.serializeToString(&byteString); @@ -229,7 +232,10 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventLis mStatsDelegate->statsEventWriteInt32( event, layer->displayRefreshRateBucket); // display_refresh_rate_bucket mStatsDelegate->statsEventWriteInt32(event, layer->renderRateBucket); // render_rate_bucket - std::string frameRateVoteBytes = frameRateVoteToProtoByteString(0.0, 0, 0); + std::string frameRateVoteBytes = + frameRateVoteToProtoByteString(layer->setFrameRateVote.frameRate, + layer->setFrameRateVote.frameRateCompatibility, + layer->setFrameRateVote.seamlessness); mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameRateVoteBytes.c_str(), frameRateVoteBytes.size()); // set_frame_rate_vote std::string appDeadlineMissedBytes = @@ -468,8 +474,10 @@ static int32_t clampToSmallestBucket(Fps fps, size_t bucketWidth) { } void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, - std::optional renderRate) { + std::optional renderRate, + SetFrameRateVote frameRateVote) { ATRACE_CALL(); + ALOGV("[%d]-flushAvailableRecordsToStatsLocked", layerId); LayerRecord& layerRecord = mTimeStatsTracker[layerId]; TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord; @@ -501,6 +509,9 @@ void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayR displayStats.stats[layerKey].uid = uid; displayStats.stats[layerKey].layerName = layerName; } + if (frameRateVote.frameRate > 0.0f) { + displayStats.stats[layerKey].setFrameRateVote = frameRateVote; + } TimeStatsHelper::TimeStatsLayer& timeStatsLayer = displayStats.stats[layerKey]; timeStatsLayer.totalFrames++; timeStatsLayer.droppedFrames += layerRecord.droppedFrames; @@ -724,7 +735,8 @@ void TimeStats::setAcquireFence(int32_t layerId, uint64_t frameNumber, } void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, - Fps displayRefreshRate, std::optional renderRate) { + Fps displayRefreshRate, std::optional renderRate, + SetFrameRateVote frameRateVote) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -743,12 +755,13 @@ void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t pr layerRecord.waitData++; } - flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate); + flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote); } void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& presentFence, - Fps displayRefreshRate, std::optional renderRate) { + Fps displayRefreshRate, std::optional renderRate, + SetFrameRateVote frameRateVote) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -768,7 +781,7 @@ void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, layerRecord.waitData++; } - flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate); + flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote); } static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL | diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index fd112b95b0..a87b7cb4a6 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -50,6 +50,8 @@ namespace android { class TimeStats { public: + using SetFrameRateVote = TimeStatsHelper::SetFrameRateVote; + virtual ~TimeStats() = default; // Called once boot has been finished to perform additional capabilities, @@ -110,10 +112,12 @@ public: // SetPresent{Time, Fence} are not expected to be called in the critical // rendering path, as they flush prior fences if those fences have fired. virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, - Fps displayRefreshRate, std::optional renderRate) = 0; + Fps displayRefreshRate, std::optional renderRate, + SetFrameRateVote frameRateVote) = 0; virtual void setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& presentFence, - Fps displayRefreshRate, std::optional renderRate) = 0; + Fps displayRefreshRate, std::optional renderRate, + SetFrameRateVote frameRateVote) = 0; // Increments janky frames, blamed to the provided {refreshRate, renderRate, uid, layerName} // key, with JankMetadata as supplementary reasons for the jank. Because FrameTimeline is the @@ -307,10 +311,11 @@ public: void setAcquireFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& acquireFence) override; void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, - Fps displayRefreshRate, std::optional renderRate) override; + Fps displayRefreshRate, std::optional renderRate, + SetFrameRateVote frameRateVote) override; void setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& presentFence, Fps displayRefreshRate, - std::optional renderRate) override; + std::optional renderRate, SetFrameRateVote frameRateVote) override; void incrementJankyFrames(const JankyFramesInfo& info) override; // Clean up the layer record @@ -334,7 +339,8 @@ private: AStatsManager_PullAtomCallbackReturn populateLayerAtom(AStatsEventList* data); bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord); void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, - std::optional renderRate); + std::optional renderRate, + SetFrameRateVote frameRateVote); void flushPowerTimeLocked(); void flushAvailableGlobalRecordsToStatsLocked(); bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName); diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp index d116b02d11..a7e7db25d7 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp +++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp @@ -91,6 +91,37 @@ std::string TimeStatsHelper::JankPayload::toString() const { return result; } +std::string TimeStatsHelper::SetFrameRateVote::toString(FrameRateCompatibility compatibility) { + switch (compatibility) { + case FrameRateCompatibility::Undefined: + return "Undefined"; + case FrameRateCompatibility::Default: + return "Default"; + case FrameRateCompatibility::ExactOrMultiple: + return "ExactOrMultiple"; + } +} + +std::string TimeStatsHelper::SetFrameRateVote::toString(Seamlessness seamlessness) { + switch (seamlessness) { + case Seamlessness::Undefined: + return "Undefined"; + case Seamlessness::ShouldBeSeamless: + return "ShouldBeSeamless"; + case Seamlessness::NotRequired: + return "NotRequired"; + } +} + +std::string TimeStatsHelper::SetFrameRateVote::toString() const { + std::string result; + StringAppendF(&result, "frameRate = %.2f\n", frameRate); + StringAppendF(&result, "frameRateCompatibility = %s\n", + toString(frameRateCompatibility).c_str()); + StringAppendF(&result, "seamlessness = %s\n", toString(seamlessness).c_str()); + return result; +} + std::string TimeStatsHelper::TimeStatsLayer::toString() const { std::string result = "\n"; StringAppendF(&result, "displayRefreshRate = %d fps\n", displayRefreshRateBucket); @@ -104,6 +135,8 @@ std::string TimeStatsHelper::TimeStatsLayer::toString() const { StringAppendF(&result, "badDesiredPresentFrames = %d\n", badDesiredPresentFrames); result.append("Jank payload for this layer:\n"); result.append(jankPayload.toString()); + result.append("SetFrateRate vote for this layer:\n"); + result.append(setFrameRateVote.toString()); const auto iter = deltas.find("present2present"); if (iter != deltas.end()) { const float averageTime = iter->second.averageTime(); diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h index 5ee28ce0f2..2b37ffef30 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h +++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h @@ -55,6 +55,28 @@ public: std::string toString() const; }; + struct SetFrameRateVote { + float frameRate = 0; + + // Needs to be in sync with atoms.proto + enum class FrameRateCompatibility { + Undefined = 0, + Default = 1, + ExactOrMultiple = 2, + } frameRateCompatibility = FrameRateCompatibility::Undefined; + + // Needs to be in sync with atoms.proto + enum class Seamlessness { + Undefined = 0, + ShouldBeSeamless = 1, + NotRequired = 2, + } seamlessness = Seamlessness::Undefined; + + static std::string toString(FrameRateCompatibility); + static std::string toString(Seamlessness); + std::string toString() const; + }; + class TimeStatsLayer { public: uid_t uid; @@ -67,6 +89,7 @@ public: int32_t lateAcquireFrames = 0; int32_t badDesiredPresentFrames = 0; JankPayload jankPayload; + SetFrameRateVote setFrameRateVote; std::unordered_map deltas; std::string toString() const; diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index a72ab42866..c1f0c4ef03 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -142,15 +142,16 @@ public: std::string inputCommand(InputCommand cmd, bool useProto); - void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts); + void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts, + TimeStats::SetFrameRateVote frameRateVote); int32_t genRandomInt32(int32_t begin, int32_t end); template void insertTimeRecord(const TimeStamp (&sequence)[N], int32_t id, uint64_t frameNumber, - nsecs_t ts) { + nsecs_t ts, TimeStats::SetFrameRateVote frameRateVote = {}) { for (size_t i = 0; i < N; i++, ts += 1000000) { - setTimeStamp(sequence[i], id, frameNumber, ts); + setTimeStamp(sequence[i], id, frameNumber, ts, frameRateVote); } } @@ -234,7 +235,8 @@ static std::string genLayerName(int32_t layerId) { return (layerId < 0 ? "PopupWindow:b54fcd1#0" : "com.example.fake#") + std::to_string(layerId); } -void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts) { +void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts, + TimeStats::SetFrameRateVote frameRateVote) { switch (type) { case TimeStamp::POST: ASSERT_NO_FATAL_FAILURE( @@ -254,13 +256,13 @@ void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumbe ASSERT_NO_FATAL_FAILURE(mTimeStats->setDesiredTime(id, frameNumber, ts)); break; case TimeStamp::PRESENT: - ASSERT_NO_FATAL_FAILURE( - mTimeStats->setPresentTime(id, frameNumber, ts, kRefreshRate0, kRenderRate0)); + ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentTime(id, frameNumber, ts, kRefreshRate0, + kRenderRate0, frameRateVote)); break; case TimeStamp::PRESENT_FENCE: - ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentFence(id, frameNumber, - std::make_shared(ts), - kRefreshRate0, kRenderRate0)); + ASSERT_NO_FATAL_FAILURE( + mTimeStats->setPresentFence(id, frameNumber, std::make_shared(ts), + kRefreshRate0, kRenderRate0, frameRateVote)); break; default: ALOGD("Invalid timestamp type"); @@ -411,6 +413,96 @@ TEST_F(TimeStatsTest, canIncreaseJankyFramesForLayer) { EXPECT_THAT(result, HasSubstr(expectedResult)); } +TEST_F(TimeStatsTest, canCaptureSetFrameRateVote) { + // this stat is not in the proto so verify by checking the string dump + EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); + + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); + + const auto frameRate60 = TimeStats::SetFrameRateVote{ + .frameRate = 60.0f, + .frameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility::Default, + .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::ShouldBeSeamless, + }; + const auto frameRate90 = TimeStats::SetFrameRateVote{ + .frameRate = 90.0f, + .frameRateCompatibility = + TimeStats::SetFrameRateVote::FrameRateCompatibility::ExactOrMultiple, + .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::NotRequired, + }; + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate60); + std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING)); + std::string expectedResult = "frameRate = 60.00"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "frameRateCompatibility = Default"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "seamlessness = ShouldBeSeamless"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000, frameRate90); + result = inputCommand(InputCommand::DUMP_ALL, FMT_STRING); + expectedResult = "frameRate = 90.00"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "frameRateCompatibility = ExactOrMultiple"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "seamlessness = NotRequired"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + + insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 4, 4000000, frameRate60); + result = inputCommand(InputCommand::DUMP_ALL, FMT_STRING); + expectedResult = "frameRate = 60.00"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "frameRateCompatibility = Default"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "seamlessness = ShouldBeSeamless"; + EXPECT_THAT(result, HasSubstr(expectedResult)); +} + +TEST_F(TimeStatsTest, canCaptureSetFrameRateVoteAfterZeroForLayer) { + // this stat is not in the proto so verify by checking the string dump + EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); + + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); + + const auto frameRate90 = TimeStats::SetFrameRateVote{ + .frameRate = 90.0f, + .frameRateCompatibility = + TimeStats::SetFrameRateVote::FrameRateCompatibility::ExactOrMultiple, + .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::NotRequired, + }; + const auto frameRateDefault = TimeStats::SetFrameRateVote{ + .frameRate = 0.0f, + .frameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility::Default, + .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::ShouldBeSeamless, + }; + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate90); + std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING)); + std::string expectedResult = "frameRate = 90.00"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "frameRateCompatibility = ExactOrMultiple"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "seamlessness = NotRequired"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000, frameRateDefault); + result = inputCommand(InputCommand::DUMP_ALL, FMT_STRING); + expectedResult = "frameRate = 90.00"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "frameRateCompatibility = ExactOrMultiple"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "seamlessness = NotRequired"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + + insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 4, 4000000, frameRateDefault); + result = inputCommand(InputCommand::DUMP_ALL, FMT_STRING); + expectedResult = "frameRate = 90.00"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "frameRateCompatibility = ExactOrMultiple"; + EXPECT_THAT(result, HasSubstr(expectedResult)); + expectedResult = "seamlessness = NotRequired"; + EXPECT_THAT(result, HasSubstr(expectedResult)); +} + TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) { // this stat is not in the proto so verify by checking the string dump constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2; @@ -936,12 +1028,15 @@ std::string buildExpectedHistogramBytestring(const std::vector& times, return byteString; } -std::string frameRateVoteToProtoByteString(float refreshRate, int frameRateCompatibility, - int seamlessness) { +std::string frameRateVoteToProtoByteString( + float refreshRate, + TimeStats::SetFrameRateVote::FrameRateCompatibility frameRateCompatibility, + TimeStats::SetFrameRateVote::Seamlessness seamlessness) { util::ProtoOutputStream proto; proto.write(android::util::FIELD_TYPE_FLOAT | 1 /* field id */, refreshRate); - proto.write(android::util::FIELD_TYPE_ENUM | 2 /* field id */, frameRateCompatibility); - proto.write(android::util::FIELD_TYPE_ENUM | 3 /* field id */, seamlessness); + proto.write(android::util::FIELD_TYPE_ENUM | 2 /* field id */, + static_cast(frameRateCompatibility)); + proto.write(android::util::FIELD_TYPE_ENUM | 3 /* field id */, static_cast(seamlessness)); std::string byteString; proto.serializeToString(&byteString); @@ -1149,7 +1244,13 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) { mTimeStats->incrementBadDesiredPresent(LAYER_ID_0); } - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000); + const auto frameRate60 = TimeStats::SetFrameRateVote{ + .frameRate = 60.0f, + .frameRateCompatibility = + TimeStats::SetFrameRateVote::FrameRateCompatibility::ExactOrMultiple, + .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::NotRequired, + }; + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate60); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3}); @@ -1181,7 +1282,10 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { std::string expectedLatchToPresent = buildExpectedHistogramBytestring({2}, {1}); std::string expectedDesiredToPresent = buildExpectedHistogramBytestring({1}, {1}); std::string expectedPostToAcquire = buildExpectedHistogramBytestring({1}, {1}); - std::string expectedFrameRateOverride = frameRateVoteToProtoByteString(0.0, 0, 0); + std::string expectedFrameRateOverride = + frameRateVoteToProtoByteString(frameRate60.frameRate, + frameRate60.frameRateCompatibility, + frameRate60.seamlessness); std::string expectedAppDeadlineMissed = buildExpectedHistogramBytestring({3, 2}, {4, 3}); { InSequence seq; @@ -1455,7 +1559,7 @@ TEST_F(TimeStatsTest, canSurviveMonkey) { TimeStamp type = static_cast(genRandomInt32(TIME_STAMP_BEGIN, TIME_STAMP_END)); const int32_t ts = genRandomInt32(1, 1000000000); ALOGV("type[%d], layerId[%d], frameNumber[%d], ts[%d]", type, layerId, frameNumber, ts); - setTimeStamp(type, layerId, frameNumber, ts); + setTimeStamp(type, layerId, frameNumber, ts, {}); } } diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h index 3e4a0b8c09..37b74ed3a7 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h @@ -48,10 +48,11 @@ public: MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t)); MOCK_METHOD3(setAcquireTime, void(int32_t, uint64_t, nsecs_t)); MOCK_METHOD3(setAcquireFence, void(int32_t, uint64_t, const std::shared_ptr&)); - MOCK_METHOD5(setPresentTime, void(int32_t, uint64_t, nsecs_t, Fps, std::optional)); - MOCK_METHOD5(setPresentFence, - void(int32_t, uint64_t, const std::shared_ptr&, Fps, - std::optional)); + MOCK_METHOD6(setPresentTime, + void(int32_t, uint64_t, nsecs_t, Fps, std::optional, SetFrameRateVote)); + MOCK_METHOD6(setPresentFence, + void(int32_t, uint64_t, const std::shared_ptr&, Fps, std::optional, + SetFrameRateVote)); MOCK_METHOD1(incrementJankyFrames, void(const JankyFramesInfo&)); MOCK_METHOD1(onDestroy, void(int32_t)); MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t)); -- cgit v1.2.3-59-g8ed1b From 0758e5d1bcf68751b3b847cc542be2ec27f9b816 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Thu, 11 Mar 2021 22:15:04 -0800 Subject: SurfaceFlinger: Remove deferTransactionUntil There are no users left Bug: 168505645 Change-Id: I81725bf3c0ef4704e9da25da9a75854b4f172885 --- cmds/surfacereplayer/proto/src/trace.proto | 6 - cmds/surfacereplayer/replayer/Replayer.cpp | 25 --- cmds/surfacereplayer/replayer/Replayer.h | 4 - libs/gui/LayerState.cpp | 10 - libs/gui/SurfaceComposerClient.cpp | 17 -- libs/gui/include/gui/LayerState.h | 4 - libs/gui/include/gui/SurfaceComposerClient.h | 8 +- services/surfaceflinger/BufferLayer.cpp | 76 -------- services/surfaceflinger/BufferLayer.h | 7 - services/surfaceflinger/BufferStateLayer.cpp | 19 -- services/surfaceflinger/BufferStateLayer.h | 9 - services/surfaceflinger/Layer.cpp | 208 +-------------------- services/surfaceflinger/Layer.h | 99 +--------- services/surfaceflinger/SurfaceFlinger.cpp | 19 -- services/surfaceflinger/SurfaceInterceptor.cpp | 28 --- services/surfaceflinger/SurfaceInterceptor.h | 2 - services/surfaceflinger/tests/LayerUpdate_test.cpp | 85 --------- .../tests/SurfaceInterceptor_test.cpp | 29 --- .../tests/fakehwc/SFFakeHwc_test.cpp | 118 ------------ .../tests/unittests/RefreshRateSelectionTest.cpp | 5 +- .../tests/unittests/SetFrameRateTest.cpp | 5 +- .../tests/unittests/TransactionFrameTracerTest.cpp | 7 +- .../unittests/TransactionSurfaceFrameTest.cpp | 82 +------- 23 files changed, 14 insertions(+), 858 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto index 06afefd3c8..3798ba73a4 100644 --- a/cmds/surfacereplayer/proto/src/trace.proto +++ b/cmds/surfacereplayer/proto/src/trace.proto @@ -46,7 +46,6 @@ message SurfaceChange { HiddenFlagChange hidden_flag = 12; OpaqueFlagChange opaque_flag = 13; SecureFlagChange secure_flag = 14; - DeferredTransactionChange deferred_transaction = 15; CornerRadiusChange corner_radius = 16; ReparentChange reparent = 17; RelativeParentChange relative_parent = 18; @@ -113,11 +112,6 @@ message SecureFlagChange { required bool secure_flag = 1; } -message DeferredTransactionChange { - required int32 layer_id = 1; - required uint64 frame_number = 2; -} - message DisplayChange { required int32 id = 1; diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index a6d9a3feb6..cfd42fec30 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -402,11 +402,6 @@ status_t Replayer::doSurfaceTransaction( case SurfaceChange::SurfaceChangeCase::kSecureFlag: setSecureFlag(transaction, change.id(), change.secure_flag()); break; - case SurfaceChange::SurfaceChangeCase::kDeferredTransaction: - waitUntilDeferredTransactionLayerExists(change.deferred_transaction(), lock); - setDeferredTransaction(transaction, change.id(), - change.deferred_transaction()); - break; case SurfaceChange::SurfaceChangeCase::kReparent: setReparentChange(transaction, change.id(), change.reparent()); break; @@ -560,19 +555,6 @@ void Replayer::setSecureFlag(SurfaceComposerClient::Transaction& t, t.setFlags(mLayers[id], flag, layer_state_t::eLayerSecure); } -void Replayer::setDeferredTransaction(SurfaceComposerClient::Transaction& t, - layer_id id, const DeferredTransactionChange& dtc) { - ALOGV("Layer %d: Setting Deferred Transaction -- layer_id=%d, " - "frame_number=%llu", - id, dtc.layer_id(), dtc.frame_number()); - if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) { - ALOGE("Layer %d not found in Deferred Transaction", dtc.layer_id()); - return; - } - - t.deferTransactionUntil_legacy(mLayers[id], mLayers[dtc.layer_id()], dtc.frame_number()); -} - void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t, display_id id, const DispSurfaceChange& /*dsc*/) { sp outProducer; @@ -676,13 +658,6 @@ void Replayer::waitUntilTimestamp(int64_t timestamp) { std::this_thread::sleep_for(std::chrono::nanoseconds(timestamp - mCurrentTime)); } -void Replayer::waitUntilDeferredTransactionLayerExists( - const DeferredTransactionChange& dtc, std::unique_lock& lock) { - if (mLayers.count(dtc.layer_id()) == 0 || mLayers[dtc.layer_id()] == nullptr) { - mLayerCond.wait(lock, [&] { return (mLayers[dtc.layer_id()] != nullptr); }); - } -} - status_t Replayer::loadSurfaceComposerClient() { mComposerClient = new SurfaceComposerClient; return mComposerClient->initCheck(); diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h index 252db2bfbb..d62522a497 100644 --- a/cmds/surfacereplayer/replayer/Replayer.h +++ b/cmds/surfacereplayer/replayer/Replayer.h @@ -110,8 +110,6 @@ class Replayer { layer_id id, const OpaqueFlagChange& ofc); void setSecureFlag(SurfaceComposerClient::Transaction& t, layer_id id, const SecureFlagChange& sfc); - void setDeferredTransaction(SurfaceComposerClient::Transaction& t, - layer_id id, const DeferredTransactionChange& dtc); void setReparentChange(SurfaceComposerClient::Transaction& t, layer_id id, const ReparentChange& c); void setRelativeParentChange(SurfaceComposerClient::Transaction& t, @@ -131,8 +129,6 @@ class Replayer { display_id id, const ProjectionChange& pc); void waitUntilTimestamp(int64_t timestamp); - void waitUntilDeferredTransactionLayerExists( - const DeferredTransactionChange& dtc, std::unique_lock& lock); status_t loadSurfaceComposerClient(); Trace mTrace; diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 809438534c..55ed7fe298 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -45,7 +45,6 @@ layer_state_t::layer_state_t() reserved(0), cornerRadius(0.0f), backgroundBlurRadius(0), - barrierFrameNumber(0), transform(0), transformToDisplayInverse(false), crop(Rect::INVALID_RECT), @@ -87,9 +86,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeUint32, mask); SAFE_PARCEL(matrix.write, output); SAFE_PARCEL(output.write, crop); - SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, barrierSurfaceControl_legacy); SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, reparentSurfaceControl); - SAFE_PARCEL(output.writeUint64, barrierFrameNumber); SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, relativeLayerSurfaceControl); SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, parentSurfaceControlForChild); SAFE_PARCEL(output.writeFloat, color.r); @@ -193,9 +190,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(matrix.read, input); SAFE_PARCEL(input.read, crop); - SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &barrierSurfaceControl_legacy); SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &reparentSurfaceControl); - SAFE_PARCEL(input.readUint64, &barrierFrameNumber); SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &relativeLayerSurfaceControl); SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &parentSurfaceControlForChild); @@ -425,11 +420,6 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eBlurRegionsChanged; blurRegions = other.blurRegions; } - if (other.what & eDeferTransaction_legacy) { - what |= eDeferTransaction_legacy; - barrierSurfaceControl_legacy = other.barrierSurfaceControl_legacy; - barrierFrameNumber = other.barrierFrameNumber; - } if (other.what & eRelativeLayerChanged) { what |= eRelativeLayerChanged; what &= ~eLayerChanged; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 9ce094aa77..e6baba6e1d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1140,23 +1140,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBlurR return *this; } -SurfaceComposerClient::Transaction& -SurfaceComposerClient::Transaction::deferTransactionUntil_legacy( - const sp& sc, const sp& barrierSurfaceControl, - uint64_t frameNumber) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - s->what |= layer_state_t::eDeferTransaction_legacy; - s->barrierSurfaceControl_legacy = barrierSurfaceControl; - s->barrierFrameNumber = frameNumber; - - registerSurfaceControlForCallback(sc); - return *this; -} - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent( const sp& sc, const sp& newParent) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 41a022f90e..d2d1e5b91c 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -82,8 +82,6 @@ struct layer_state_t { eTransparentRegionChanged = 0x00000020, eFlagsChanged = 0x00000040, eLayerStackChanged = 0x00000080, - /* was eCropChanged_legacy, now available 0x00000100, */ - eDeferTransaction_legacy = 0x00000200, eReleaseBufferListenerChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, /* was eDetachChildren, now available 0x00002000, */ @@ -152,9 +150,7 @@ struct layer_state_t { matrix22_t matrix; float cornerRadius; uint32_t backgroundBlurRadius; - sp barrierSurfaceControl_legacy; sp reparentSurfaceControl; - uint64_t barrierFrameNumber; sp relativeLayerSurfaceControl; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 1590b10a00..fe6a30aa42 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -454,13 +454,7 @@ public: const std::vector& regions); Transaction& setLayerStack(const sp& sc, uint32_t layerStack); Transaction& setMetadata(const sp& sc, uint32_t key, const Parcel& p); - // Defers applying any changes made in this transaction until the Layer - // identified by handle reaches the given frameNumber. If the Layer identified - // by handle is removed, then we will apply this transaction regardless of - // what frame number has been reached. - Transaction& deferTransactionUntil_legacy(const sp& sc, - const sp& barrierSurfaceControl, - uint64_t frameNumber); + /// Reparents the current layer to the new parent handle. The new parent must not be null. Transaction& reparent(const sp& sc, const sp& newParent); diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index be9bce0795..12f63dbbf1 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -507,11 +507,6 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, BufferInfo oldBufferInfo = mBufferInfo; - if (!allTransactionsSignaled(expectedPresentTime)) { - mFlinger->setTransactionFlags(eTraversalNeeded); - return false; - } - status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime); if (err != NO_ERROR) { return false; @@ -556,53 +551,9 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, recomputeVisibleRegions = true; } - // Remove any sync points corresponding to the buffer which was just - // latched - { - Mutex::Autolock lock(mLocalSyncPointMutex); - auto point = mLocalSyncPoints.begin(); - while (point != mLocalSyncPoints.end()) { - if (!(*point)->frameIsAvailable() || !(*point)->transactionIsApplied()) { - // This sync point must have been added since we started - // latching. Don't drop it yet. - ++point; - continue; - } - - if ((*point)->getFrameNumber() <= mCurrentFrameNumber) { - std::stringstream ss; - ss << "Dropping sync point " << (*point)->getFrameNumber(); - ATRACE_NAME(ss.str().c_str()); - point = mLocalSyncPoints.erase(point); - } else { - ++point; - } - } - } - return true; } -// transaction -void BufferLayer::notifyAvailableFrames(nsecs_t expectedPresentTime) { - const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime); - const bool headFenceSignaled = fenceHasSignaled(); - const bool presentTimeIsCurrent = framePresentTimeIsCurrent(expectedPresentTime); - Mutex::Autolock lock(mLocalSyncPointMutex); - for (auto& point : mLocalSyncPoints) { - if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled && - presentTimeIsCurrent) { - point->setFrameAvailable(); - sp requestedSyncLayer = point->getRequestedSyncLayer(); - if (requestedSyncLayer) { - // Need to update the transaction flag to ensure the layer's pending transaction - // gets applied. - requestedSyncLayer->setTransactionFlags(eTransactionNeeded); - } - } - } -} - bool BufferLayer::hasReadyFrame() const { return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh(); } @@ -616,33 +567,6 @@ bool BufferLayer::isProtected() const { return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED); } -// h/w composer set-up -bool BufferLayer::allTransactionsSignaled(nsecs_t expectedPresentTime) { - const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime); - bool matchingFramesFound = false; - bool allTransactionsApplied = true; - Mutex::Autolock lock(mLocalSyncPointMutex); - - for (auto& point : mLocalSyncPoints) { - if (point->getFrameNumber() > headFrameNumber) { - break; - } - matchingFramesFound = true; - - if (!point->frameIsAvailable()) { - // We haven't notified the remote layer that the frame for - // this point is available yet. Notify it now, and then - // abort this attempt to latch. - point->setFrameAvailable(); - allTransactionsApplied = false; - break; - } - - allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied(); - } - return !matchingFramesFound || allTransactionsApplied; -} - // As documented in libhardware header, formats in the range // 0x100 - 0x1FF are specific to the HAL implementation, and // are known to have no alpha channel diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index b8d3f12322..0a5235aa08 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -90,8 +90,6 @@ public: bool isBufferLatched() const override { return mRefreshPending; } - void notifyAvailableFrames(nsecs_t expectedPresentTime) override; - bool hasReadyFrame() const override; // Returns the current scaling mode @@ -153,11 +151,6 @@ protected: bool onPreComposition(nsecs_t) override; void preparePerFrameCompositionState() override; - // Check all of the local sync points to ensure that all transactions - // which need to have been applied prior to the frame which is about to - // be latched have signaled - bool allTransactionsSignaled(nsecs_t expectedPresentTime); - static bool getOpacityForFormat(uint32_t format); // from graphics API diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index ed826a0100..fa9cecf787 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -259,25 +259,6 @@ bool BufferStateLayer::willPresentCurrentTransaction() const { (mCurrentState.buffer != nullptr || mCurrentState.bgColorLayer != nullptr))); } -/* TODO: vhau uncomment once deferred transaction migration complete in - * WindowManager -void BufferStateLayer::pushPendingState() { - if (!mCurrentState.modified) { - return; - } - mPendingStates.push_back(mCurrentState); - ATRACE_INT(mTransactionName.c_str(), mPendingStates.size()); -} -*/ - -bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) { - mCurrentStateModified = mCurrentState.modified; - bool stateUpdateAvailable = Layer::applyPendingStates(stateToCommit); - mCurrentStateModified = stateUpdateAvailable && mCurrentStateModified; - mCurrentState.modified = false; - return stateUpdateAvailable; -} - Rect BufferStateLayer::getCrop(const Layer::State& s) const { return s.crop; } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 8ce3e1f55b..24e0ad290f 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -50,10 +50,6 @@ public: uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override { return flags; } - /*TODO:vhau return to using BufferStateLayer override once WM - * has removed deferred transactions! - void pushPendingState() override;*/ - bool applyPendingStates(Layer::State* stateToCommit) override; uint32_t getActiveWidth(const Layer::State& s) const override { return s.width; } uint32_t getActiveHeight(const Layer::State& s) const override { return s.height; } @@ -87,10 +83,6 @@ public: // Override to ignore legacy layer state properties that are not used by BufferStateLayer bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; } bool setTransparentRegionHint(const Region& transparent) override; - void deferTransactionUntil_legacy(const sp& /*barrierHandle*/, - uint64_t /*frameNumber*/) override {} - void deferTransactionUntil_legacy(const sp& /*barrierLayer*/, - uint64_t /*frameNumber*/) override {} Rect getBufferSize(const State& s) const override; FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; @@ -165,7 +157,6 @@ private: uint64_t mPreviousBufferId = 0; uint64_t mPreviousReleasedFrameNumber = 0; - mutable bool mCurrentStateModified = false; bool mReleasePreviousBuffer = false; // Stores the last set acquire fence signal time used to populate the callback handle's acquire diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 6038658ee6..ebf845cb95 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -202,19 +202,6 @@ LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp client, */ void Layer::onLayerDisplayed(const sp& /*releaseFence*/) {} -void Layer::removeRemoteSyncPoints() { - for (auto& point : mRemoteSyncPoints) { - point->setTransactionApplied(); - } - mRemoteSyncPoints.clear(); - - { - for (State pendingState : mPendingStates) { - pendingState.barrierLayer_legacy = nullptr; - } - } -} - void Layer::removeRelativeZ(const std::vector& layersInTree) { if (mCurrentState.zOrderRelativeOf == nullptr) { return; @@ -236,21 +223,6 @@ void Layer::removeRelativeZ(const std::vector& layersInTree) { void Layer::removeFromCurrentState() { mRemovedFromCurrentState = true; - // Since we are no longer reachable from CurrentState SurfaceFlinger - // will no longer invoke doTransaction for us, and so we will - // never finish applying transactions. We signal the sync point - // now so that another layer will not become indefinitely - // blocked. - removeRemoteSyncPoints(); - - { - Mutex::Autolock syncLock(mLocalSyncPointMutex); - for (auto& point : mLocalSyncPoints) { - point->setFrameAvailable(); - } - mLocalSyncPoints.clear(); - } - mFlinger->markLayerPendingRemovalLocked(this); } @@ -775,21 +747,6 @@ Hwc2::IComposerClient::Composition Layer::getCompositionType(const DisplayDevice } } -bool Layer::addSyncPoint(const std::shared_ptr& point) { - if (point->getFrameNumber() <= mCurrentFrameNumber) { - // Don't bother with a SyncPoint, since we've already latched the - // relevant frame - return false; - } - if (isRemovedFromCurrentState()) { - return false; - } - - Mutex::Autolock lock(mLocalSyncPointMutex); - mLocalSyncPoints.push_back(point); - return true; -} - // ---------------------------------------------------------------------------- // local state // ---------------------------------------------------------------------------- @@ -808,132 +765,6 @@ bool Layer::isSecure() const { // transaction // ---------------------------------------------------------------------------- -void Layer::pushPendingState() { - if (!mCurrentState.modified) { - return; - } - ATRACE_CALL(); - - // If this transaction is waiting on the receipt of a frame, generate a sync - // point and send it to the remote layer. - // We don't allow installing sync points after we are removed from the current state - // as we won't be able to signal our end. - if (mCurrentState.barrierLayer_legacy != nullptr && !isRemovedFromCurrentState()) { - sp barrierLayer = mCurrentState.barrierLayer_legacy.promote(); - if (barrierLayer == nullptr) { - ALOGE("[%s] Unable to promote barrier Layer.", getDebugName()); - // If we can't promote the layer we are intended to wait on, - // then it is expired or otherwise invalid. Allow this transaction - // to be applied as per normal (no synchronization). - mCurrentState.barrierLayer_legacy = nullptr; - } else { - auto syncPoint = std::make_shared(mCurrentState.barrierFrameNumber, this, - barrierLayer); - if (barrierLayer->addSyncPoint(syncPoint)) { - std::stringstream ss; - ss << "Adding sync point " << mCurrentState.barrierFrameNumber; - ATRACE_NAME(ss.str().c_str()); - mRemoteSyncPoints.push_back(std::move(syncPoint)); - } else { - // We already missed the frame we're supposed to synchronize - // on, so go ahead and apply the state update - mCurrentState.barrierLayer_legacy = nullptr; - } - } - - // Wake us up to check if the frame has been received - setTransactionFlags(eTransactionNeeded); - mFlinger->setTransactionFlags(eTraversalNeeded); - } - if (mCurrentState.bufferlessSurfaceFramesTX.size() >= State::kStateSurfaceFramesThreshold) { - // Ideally, the currentState would only contain one SurfaceFrame per transaction (assuming - // each Tx uses a different token). We don't expect the current state to hold a huge amount - // of SurfaceFrames. However, in the event it happens, this debug statement will leave a - // trail that can help in debugging. - ALOGW("Bufferless SurfaceFrames size on current state of layer %s is %" PRIu32 "", - mName.c_str(), static_cast(mCurrentState.bufferlessSurfaceFramesTX.size())); - } - mPendingStates.push_back(mCurrentState); - // Since the current state along with the SurfaceFrames has been pushed into the pendingState, - // we no longer need to retain them. If multiple states are pushed and applied together, we have - // a merging logic to address the SurfaceFrames at mergeSurfaceFrames(). - mCurrentState.bufferlessSurfaceFramesTX.clear(); - ATRACE_INT(mTransactionName.c_str(), mPendingStates.size()); -} - -void Layer::mergeSurfaceFrames(State& source, State& target) { - // No need to merge BufferSurfaceFrame as the target's surfaceFrame, if it exists, will be used - // directly. Dropping of source's SurfaceFrame is taken care of at setBuffer(). - target.bufferlessSurfaceFramesTX.merge(source.bufferlessSurfaceFramesTX); - source.bufferlessSurfaceFramesTX.clear(); -} - -void Layer::popPendingState(State* stateToCommit) { - ATRACE_CALL(); - - mergeSurfaceFrames(*stateToCommit, mPendingStates[0]); - *stateToCommit = mPendingStates[0]; - mPendingStates.pop_front(); - ATRACE_INT(mTransactionName.c_str(), mPendingStates.size()); -} - -bool Layer::applyPendingStates(State* stateToCommit) { - bool stateUpdateAvailable = false; - while (!mPendingStates.empty()) { - if (mPendingStates[0].barrierLayer_legacy != nullptr) { - if (mRemoteSyncPoints.empty()) { - // If we don't have a sync point for this, apply it anyway. It - // will be visually wrong, but it should keep us from getting - // into too much trouble. - ALOGV("[%s] No local sync point found", getDebugName()); - popPendingState(stateToCommit); - stateUpdateAvailable = true; - continue; - } - - if (mRemoteSyncPoints.front()->getFrameNumber() != - mPendingStates[0].barrierFrameNumber) { - ALOGE("[%s] Unexpected sync point frame number found", getDebugName()); - - // Signal our end of the sync point and then dispose of it - mRemoteSyncPoints.front()->setTransactionApplied(); - mRemoteSyncPoints.pop_front(); - continue; - } - - if (mRemoteSyncPoints.front()->frameIsAvailable()) { - ATRACE_NAME("frameIsAvailable"); - // Apply the state update - popPendingState(stateToCommit); - stateUpdateAvailable = true; - - // Signal our end of the sync point and then dispose of it - mRemoteSyncPoints.front()->setTransactionApplied(); - mRemoteSyncPoints.pop_front(); - } else { - ATRACE_NAME("!frameIsAvailable"); - mRemoteSyncPoints.front()->checkTimeoutAndLog(); - break; - } - } else { - popPendingState(stateToCommit); - stateUpdateAvailable = true; - } - } - - // If we still have pending updates, we need to ensure SurfaceFlinger - // will keep calling doTransaction, and so we force a traversal. - // However, our pending states won't clear until a frame is available, - // and so there is no need to specifically trigger a wakeup. - if (!mPendingStates.empty()) { - setTransactionFlags(eTransactionNeeded); - mFlinger->setTraversalNeeded(); - } - - mCurrentState.modified = false; - return stateUpdateAvailable; -} - uint32_t Layer::doTransactionResize(uint32_t flags, State* stateToCommit) { const State& s(getDrawingState()); @@ -1014,15 +845,14 @@ uint32_t Layer::doTransaction(uint32_t flags) { mChildrenChanged = false; } - pushPendingState(); - State c = getCurrentState(); - if (!applyPendingStates(&c)) { - return flags; - } + // TODO: This is unfortunate. + mCurrentStateModified = mCurrentState.modified; + mCurrentState.modified = false; - flags = doTransactionResize(flags, &c); + flags = doTransactionResize(flags, &mCurrentState); const State& s(getDrawingState()); + State& c(getCurrentState()); if (getActiveGeometry(c) != getActiveGeometry(s)) { // invalidate and recompute the visible regions if needed @@ -1054,7 +884,6 @@ uint32_t Layer::doTransaction(uint32_t flags) { // Commit the transaction commitTransaction(c); - mPendingStatesSnapshot = mPendingStates; mCurrentState.callbackHandles = {}; return flags; @@ -1662,25 +1491,6 @@ Layer::FrameRate Layer::getFrameRateForLayerTree() const { return frameRate; } -void Layer::deferTransactionUntil_legacy(const sp& barrierLayer, uint64_t frameNumber) { - ATRACE_CALL(); - - mCurrentState.barrierLayer_legacy = barrierLayer; - mCurrentState.barrierFrameNumber = frameNumber; - // We don't set eTransactionNeeded, because just receiving a deferral - // request without any other state updates shouldn't actually induce a delay - mCurrentState.modified = true; - pushPendingState(); - mCurrentState.barrierLayer_legacy = nullptr; - mCurrentState.barrierFrameNumber = 0; - mCurrentState.modified = false; -} - -void Layer::deferTransactionUntil_legacy(const sp& barrierHandle, uint64_t frameNumber) { - sp handle = static_cast(barrierHandle.get()); - deferTransactionUntil_legacy(handle->owner.promote(), frameNumber); -} - // ---------------------------------------------------------------------------- // pageflip handling... // ---------------------------------------------------------------------------- @@ -2362,14 +2172,6 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, const ui::Transform transform = getTransform(); if (traceFlags & SurfaceTracing::TRACE_CRITICAL) { - for (const auto& pendingState : mPendingStatesSnapshot) { - auto barrierLayer = pendingState.barrierLayer_legacy.promote(); - if (barrierLayer != nullptr) { - BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer(); - barrierLayerProto->set_id(barrierLayer->sequence); - barrierLayerProto->set_frame_number(pendingState.barrierFrameNumber); - } - } auto buffer = getBuffer(); if (buffer != nullptr) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 5528a8190f..304eb36b9d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -166,11 +166,6 @@ public: Rect crop; Rect requestedCrop; - // If set, defers this state update until the identified Layer - // receives a frame with the given frameNumber - wp barrierLayer_legacy; - uint64_t barrierFrameNumber; - // the transparentRegion hint is a bit special, it's latched only // when we receive a buffer -- this is because it's "content" // dependent. @@ -398,9 +393,6 @@ public: virtual bool setFlags(uint32_t flags, uint32_t mask); virtual bool setLayerStack(uint32_t layerStack); virtual uint32_t getLayerStack() const; - virtual void deferTransactionUntil_legacy(const sp& barrierHandle, - uint64_t frameNumber); - virtual void deferTransactionUntil_legacy(const sp& barrierLayer, uint64_t frameNumber); virtual bool setMetadata(const LayerMetadata& data); virtual void setChildrenDrawingParent(const sp&); virtual bool reparent(const sp& newParentHandle); @@ -578,14 +570,6 @@ public: virtual int32_t getQueuedFrameCount() const { return 0; } - virtual void pushPendingState(); - - /* - * Merges the BufferlessSurfaceFrames from source with the target. If the same token exists in - * both source and target, target's SurfaceFrame will be retained. - */ - void mergeSurfaceFrames(State& source, State& target); - /** * Returns active buffer size in the correct orientation. Buffer size is determined by undoing * any buffer transformations. If the layer has no buffer then return INVALID_RECT. @@ -615,7 +599,6 @@ public: // ignored. virtual RoundedCornerState getRoundedCornerState() const; - virtual void notifyAvailableFrames(nsecs_t /*expectedPresentTime*/) {} virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; } /** * Return whether this layer needs an input info. For most layer types @@ -903,65 +886,6 @@ public: virtual std::string getPendingBufferCounterName() { return ""; } protected: - class SyncPoint { - public: - explicit SyncPoint(uint64_t frameNumber, wp requestedSyncLayer, - wp barrierLayer_legacy) - : mFrameNumber(frameNumber), - mFrameIsAvailable(false), - mTransactionIsApplied(false), - mRequestedSyncLayer(requestedSyncLayer), - mBarrierLayer_legacy(barrierLayer_legacy) {} - uint64_t getFrameNumber() const { return mFrameNumber; } - - bool frameIsAvailable() const { return mFrameIsAvailable; } - - void setFrameAvailable() { mFrameIsAvailable = true; } - - bool transactionIsApplied() const { return mTransactionIsApplied; } - - void setTransactionApplied() { mTransactionIsApplied = true; } - - sp getRequestedSyncLayer() { return mRequestedSyncLayer.promote(); } - - sp getBarrierLayer() const { return mBarrierLayer_legacy.promote(); } - - bool isTimeout() const { - using namespace std::chrono_literals; - static constexpr std::chrono::nanoseconds TIMEOUT_THRESHOLD = 1s; - - return std::chrono::steady_clock::now() - mCreateTimeStamp > TIMEOUT_THRESHOLD; - } - - void checkTimeoutAndLog() { - using namespace std::chrono_literals; - static constexpr std::chrono::nanoseconds LOG_PERIOD = 1s; - - if (!frameIsAvailable() && isTimeout()) { - const auto now = std::chrono::steady_clock::now(); - if (now - mLastLogTime > LOG_PERIOD) { - mLastLogTime = now; - sp requestedSyncLayer = getRequestedSyncLayer(); - sp barrierLayer = getBarrierLayer(); - ALOGW("[%s] sync point %" PRIu64 " wait timeout %lld for %s", - requestedSyncLayer ? requestedSyncLayer->getDebugName() : "Removed", - mFrameNumber, (now - mCreateTimeStamp).count(), - barrierLayer ? barrierLayer->getDebugName() : "Removed"); - } - } - } - - private: - const uint64_t mFrameNumber; - std::atomic mFrameIsAvailable; - std::atomic mTransactionIsApplied; - wp mRequestedSyncLayer; - wp mBarrierLayer_legacy; - const std::chrono::time_point mCreateTimeStamp = - std::chrono::steady_clock::now(); - std::chrono::time_point mLastLogTime; - }; - friend class impl::SurfaceInterceptor; // For unit tests @@ -980,7 +904,6 @@ protected: ui::Dataspace outputDataspace); virtual void preparePerFrameCompositionState(); virtual void commitTransaction(State& stateToCommit); - virtual bool applyPendingStates(State* stateToCommit); virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit); virtual void onSurfaceFrameCreated(const std::shared_ptr&) {} @@ -1026,21 +949,6 @@ protected: virtual ui::Transform getInputTransform() const; virtual Rect getInputBounds() const; - // SyncPoints which will be signaled when the correct frame is at the head - // of the queue and dropped after the frame has been latched. Protected by - // mLocalSyncPointMutex. - Mutex mLocalSyncPointMutex; - std::list> mLocalSyncPoints; - - // SyncPoints which will be signaled and then dropped when the transaction - // is applied - std::list> mRemoteSyncPoints; - - // Returns false if the relevant frame has already been latched - bool addSyncPoint(const std::shared_ptr& point); - - void popPendingState(State* stateToCommit); - // constant sp mFlinger; @@ -1050,14 +958,10 @@ protected: // These are only accessed by the main thread or the tracing thread. State mDrawingState; - // Store a copy of the pending state so that the drawing thread can access the - // states without a lock. - std::deque mPendingStatesSnapshot; // these are protected by an external lock (mStateLock) State mCurrentState; std::atomic mTransactionFlags{0}; - std::deque mPendingStates; // Timestamp history for UIAutomation. Thread safe. FrameTracker mFrameTracker; @@ -1119,6 +1023,8 @@ protected: // Used in buffer stuffing analysis in FrameTimeline. nsecs_t mLastLatchTime = 0; + mutable bool mCurrentStateModified = false; + private: virtual void setTransformHint(ui::Transform::RotationFlags) {} @@ -1143,7 +1049,6 @@ private: void updateTreeHasFrameRateVote(); void setZOrderRelativeOf(const wp& relativeOf); - void removeRemoteSyncPoints(); // Find the root of the cloned hierarchy, this means the first non cloned parent. // This will return null if first non cloned parent is not found. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 02579c6bde..274d2833b2 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2815,13 +2815,6 @@ void SurfaceFlinger::processDisplayChangesLocked() { } void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { - const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); - - // Notify all layers of available frames - mCurrentState.traverse([expectedPresentTime](Layer* layer) { - layer->notifyAvailableFrames(expectedPresentTime); - }); - /* * Traversal of the children * (perform the transaction for each of them if needed) @@ -3833,12 +3826,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( const uint64_t what = s.what; - // If we are deferring transaction, make sure to push the pending state, as otherwise the - // pending state will also be deferred. - if (what & layer_state_t::eDeferTransaction_legacy) { - layer->pushPendingState(); - } - // Only set by BLAST adapter layers if (what & layer_state_t::eProducerDisconnect) { layer->onDisconnect(); @@ -3973,12 +3960,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTransactionNeeded | eTraversalNeeded | eTransformHintUpdateNeeded; } } - if (what & layer_state_t::eDeferTransaction_legacy) { - layer->deferTransactionUntil_legacy(s.barrierSurfaceControl_legacy->getHandle(), - s.barrierFrameNumber); - // We don't trigger a traversal here because if no other state is - // changed, we don't want this to cause any more work - } if (what & layer_state_t::eTransformChanged) { if (layer->setTransform(s.transform)) flags |= eTraversalNeeded; } diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index b49562a0a5..113f463c39 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -141,11 +141,6 @@ void SurfaceInterceptor::addInitialSurfaceStateLocked(Increment* increment, addCornerRadiusLocked(transaction, layerId, layer->mCurrentState.cornerRadius); addBackgroundBlurRadiusLocked(transaction, layerId, layer->mCurrentState.backgroundBlurRadius); addBlurRegionsLocked(transaction, layerId, layer->mCurrentState.blurRegions); - if (layer->mCurrentState.barrierLayer_legacy != nullptr) { - addDeferTransactionLocked(transaction, layerId, - layer->mCurrentState.barrierLayer_legacy.promote(), - layer->mCurrentState.barrierFrameNumber); - } addFlagsLocked(transaction, layerId, layer->mCurrentState.flags, layer_state_t::eLayerHidden | layer_state_t::eLayerOpaque | layer_state_t::eLayerSecure); @@ -380,20 +375,6 @@ void SurfaceInterceptor::addBlurRegionsLocked(Transaction* transaction, int32_t } } -void SurfaceInterceptor::addDeferTransactionLocked(Transaction* transaction, int32_t layerId, - const sp& layer, uint64_t frameNumber) -{ - SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); - if (layer == nullptr) { - ALOGE("An existing layer could not be retrieved with the handle" - " for the deferred transaction"); - return; - } - DeferredTransactionChange* deferTransaction(change->mutable_deferred_transaction()); - deferTransaction->set_layer_id(getLayerId(layer)); - deferTransaction->set_frame_number(frameNumber); -} - void SurfaceInterceptor::addReparentLocked(Transaction* transaction, int32_t layerId, int32_t parentId) { SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); @@ -464,15 +445,6 @@ void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction, if (state.what & layer_state_t::eBlurRegionsChanged) { addBlurRegionsLocked(transaction, layerId, state.blurRegions); } - if (state.what & layer_state_t::eDeferTransaction_legacy) { - sp otherLayer = nullptr; - if (state.barrierSurfaceControl_legacy != nullptr) { - otherLayer = static_cast( - state.barrierSurfaceControl_legacy->getHandle().get()) - ->owner.promote(); - } - addDeferTransactionLocked(transaction, layerId, otherLayer, state.barrierFrameNumber); - } if (state.what & layer_state_t::eReparent) { auto parentHandle = (state.parentSurfaceControlForChild) ? state.parentSurfaceControlForChild->getHandle() diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h index d2cbf40426..30aca8340e 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -167,8 +167,6 @@ private: int32_t backgroundBlurRadius); void addBlurRegionsLocked(Transaction* transaction, int32_t layerId, const std::vector& effectRegions); - void addDeferTransactionLocked(Transaction* transaction, int32_t layerId, - const sp& layer, uint64_t frameNumber); void addSurfaceChangesLocked(Transaction* transaction, const layer_state_t& state); void addTransactionLocked(Increment* increment, const Vector& stateUpdates, const DefaultKeyedVector, DisplayDeviceState>& displays, diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index 39d9206e1a..adb5d58e8c 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -160,61 +160,6 @@ protected: } }; -TEST_F(LayerUpdateTest, DeferredTransactionTest) { - std::unique_ptr sc; - { - SCOPED_TRACE("before anything"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(32, 32); - sc->expectFGColor(96, 96); - sc->expectBGColor(160, 160); - } - - // set up two deferred transactions on different frames - asTransaction([&](Transaction& t) { - t.setAlpha(mFGSurfaceControl, 0.75); - t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl, - mSyncSurfaceControl->getSurface()->getNextFrameNumber()); - }); - - asTransaction([&](Transaction& t) { - t.setPosition(mFGSurfaceControl, 128, 128); - t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl, - mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1); - }); - - { - SCOPED_TRACE("before any trigger"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(32, 32); - sc->expectFGColor(96, 96); - sc->expectBGColor(160, 160); - } - - // should trigger the first deferred transaction, but not the second one - TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); - { - SCOPED_TRACE("after first trigger"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(32, 32); - sc->checkPixel(96, 96, 162, 63, 96); - sc->expectBGColor(160, 160); - } - - // should show up immediately since it's not deferred - asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 1.0); }); - - // trigger the second deferred transaction - TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); - { - SCOPED_TRACE("after second trigger"); - ScreenCapture::captureScreen(&sc); - sc->expectBGColor(32, 32); - sc->expectBGColor(96, 96); - sc->expectFGColor(160, 160); - } -} - TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) { std::unique_ptr sc; @@ -702,36 +647,6 @@ TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) { } } -TEST_F(ChildLayerTest, Bug36858924) { - // Destroy the child layer - mChild.clear(); - - // Now recreate it as hidden - mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eHidden, mFGSurfaceControl.get()); - - // Show the child layer in a deferred transaction - asTransaction([&](Transaction& t) { - t.deferTransactionUntil_legacy(mChild, mFGSurfaceControl, - mFGSurfaceControl->getSurface()->getNextFrameNumber()); - t.show(mChild); - }); - - // Render the foreground surface a few times - // - // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third - // frame because SurfaceFlinger would never process the deferred transaction and would therefore - // never acquire/release the first buffer - ALOGI("Filling 1"); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0); - ALOGI("Filling 2"); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 0, 255); - ALOGI("Filling 3"); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 255, 0, 0); - ALOGI("Filling 4"); - TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0); -} - TEST_F(ChildLayerTest, Reparent) { asTransaction([&](Transaction& t) { t.show(mChild); diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 09bd775872..af23e2a9cc 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -44,7 +44,6 @@ constexpr uint32_t BUFFER_UPDATES = 18; constexpr uint32_t LAYER_UPDATE = INT_MAX - 2; constexpr uint32_t SIZE_UPDATE = 134; constexpr uint32_t STACK_UPDATE = 1; -constexpr uint64_t DEFERRED_UPDATE = 0; constexpr int32_t RELATIVE_Z = 42; constexpr float ALPHA_UPDATE = 0.29f; constexpr float CORNER_RADIUS_UPDATE = 0.2f; @@ -191,7 +190,6 @@ public: bool hiddenFlagUpdateFound(const SurfaceChange& change, bool foundHiddenFlag); bool opaqueFlagUpdateFound(const SurfaceChange& change, bool foundOpaqueFlag); bool secureFlagUpdateFound(const SurfaceChange& change, bool foundSecureFlag); - bool deferredTransactionUpdateFound(const SurfaceChange& change, bool foundDeferred); bool reparentUpdateFound(const SurfaceChange& change, bool found); bool relativeParentUpdateFound(const SurfaceChange& change, bool found); bool shadowRadiusUpdateFound(const SurfaceChange& change, bool found); @@ -227,7 +225,6 @@ public: void hiddenFlagUpdate(Transaction&); void opaqueFlagUpdate(Transaction&); void secureFlagUpdate(Transaction&); - void deferredTransactionUpdate(Transaction&); void reparentUpdate(Transaction&); void relativeParentUpdate(Transaction&); void shadowRadiusUpdate(Transaction&); @@ -396,10 +393,6 @@ void SurfaceInterceptorTest::secureFlagUpdate(Transaction& t) { t.setFlags(mBGSurfaceControl, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure); } -void SurfaceInterceptorTest::deferredTransactionUpdate(Transaction& t) { - t.deferTransactionUntil_legacy(mBGSurfaceControl, mBGSurfaceControl, DEFERRED_UPDATE); -} - void SurfaceInterceptorTest::reparentUpdate(Transaction& t) { t.reparent(mBGSurfaceControl, mFGSurfaceControl); } @@ -437,7 +430,6 @@ void SurfaceInterceptorTest::runAllUpdates() { runInTransaction(&SurfaceInterceptorTest::hiddenFlagUpdate); runInTransaction(&SurfaceInterceptorTest::opaqueFlagUpdate); runInTransaction(&SurfaceInterceptorTest::secureFlagUpdate); - runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate); runInTransaction(&SurfaceInterceptorTest::reparentUpdate); runInTransaction(&SurfaceInterceptorTest::relativeParentUpdate); runInTransaction(&SurfaceInterceptorTest::shadowRadiusUpdate); @@ -621,18 +613,6 @@ bool SurfaceInterceptorTest::secureFlagUpdateFound(const SurfaceChange& change, return foundSecureFlag; } -bool SurfaceInterceptorTest::deferredTransactionUpdateFound(const SurfaceChange& change, - bool foundDeferred) { - bool hasId(change.deferred_transaction().layer_id() == mBGLayerId); - bool hasFrameNumber(change.deferred_transaction().frame_number() == DEFERRED_UPDATE); - if (hasId && hasFrameNumber && !foundDeferred) { - foundDeferred = true; - } else if (hasId && hasFrameNumber && foundDeferred) { - [] () { FAIL(); }(); - } - return foundDeferred; -} - bool SurfaceInterceptorTest::reparentUpdateFound(const SurfaceChange& change, bool found) { bool hasId(change.reparent().parent_id() == mFGLayerId); if (hasId && !found) { @@ -715,9 +695,6 @@ bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace, case SurfaceChange::SurfaceChangeCase::kSecureFlag: foundUpdate = secureFlagUpdateFound(change, foundUpdate); break; - case SurfaceChange::SurfaceChangeCase::kDeferredTransaction: - foundUpdate = deferredTransactionUpdateFound(change, foundUpdate); - break; case SurfaceChange::SurfaceChangeCase::kReparent: foundUpdate = reparentUpdateFound(change, foundUpdate); break; @@ -749,7 +726,6 @@ void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) { ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kHiddenFlag)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kOpaqueFlag)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kSecureFlag)); - ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kDeferredTransaction)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparent)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kRelativeParent)); } @@ -906,11 +882,6 @@ TEST_F(SurfaceInterceptorTest, InterceptSecureFlagUpdateWorks) { SurfaceChange::SurfaceChangeCase::kSecureFlag); } -TEST_F(SurfaceInterceptorTest, InterceptDeferredTransactionUpdateWorks) { - captureTest(&SurfaceInterceptorTest::deferredTransactionUpdate, - SurfaceChange::SurfaceChangeCase::kDeferredTransaction); -} - TEST_F(SurfaceInterceptorTest, InterceptReparentUpdateWorks) { captureTest(&SurfaceInterceptorTest::reparentUpdate, SurfaceChange::SurfaceChangeCase::kReparent); diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index c081f9b642..eb31e2eca1 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -91,7 +91,6 @@ constexpr static TestColor RED = {195, 63, 63, 255}; constexpr static TestColor LIGHT_RED = {255, 177, 177, 255}; constexpr static TestColor GREEN = {63, 195, 63, 255}; constexpr static TestColor BLUE = {63, 63, 195, 255}; -constexpr static TestColor DARK_GRAY = {63, 63, 63, 255}; constexpr static TestColor LIGHT_GRAY = {200, 200, 200, 255}; // Fill an RGBA_8888 formatted surface with a single color. @@ -1469,77 +1468,6 @@ protected: } } - void Test_DeferredTransaction() { - // Synchronization surface - constexpr static int SYNC_LAYER = 2; - auto syncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1, - PIXEL_FORMAT_RGBA_8888, 0); - ASSERT_TRUE(syncSurfaceControl != nullptr); - ASSERT_TRUE(syncSurfaceControl->isValid()); - - fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); - - { - TransactionScope ts(*sFakeComposer); - ts.setLayer(syncSurfaceControl, INT32_MAX - 1); - ts.setPosition(syncSurfaceControl, mDisplayWidth - 2, mDisplayHeight - 2); - ts.show(syncSurfaceControl); - } - auto referenceFrame = mBaseFrame; - referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2, - mDisplayWidth - 1, mDisplayHeight - 1)); - referenceFrame[SYNC_LAYER].mSwapCount = 1; - EXPECT_EQ(2, sFakeComposer->getFrameCount()); - EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); - - // set up two deferred transactions on different frames - these should not yield composited - // frames - { - TransactionScope ts(*sFakeComposer); - ts.setAlpha(mFGSurfaceControl, 0.75); - ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl, - syncSurfaceControl->getSurface()->getNextFrameNumber()); - } - EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); - - { - TransactionScope ts(*sFakeComposer); - ts.setPosition(mFGSurfaceControl, 128, 128); - ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl, - syncSurfaceControl->getSurface()->getNextFrameNumber() + - 1); - } - EXPECT_EQ(4, sFakeComposer->getFrameCount()); - EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); - - // should trigger the first deferred transaction, but not the second one - fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); - sFakeComposer->runVSyncAndWait(); - EXPECT_EQ(5, sFakeComposer->getFrameCount()); - - referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f; - referenceFrame[SYNC_LAYER].mSwapCount++; - EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); - - // should show up immediately since it's not deferred - { - TransactionScope ts(*sFakeComposer); - ts.setAlpha(mFGSurfaceControl, 1.0); - } - referenceFrame[FG_LAYER].mPlaneAlpha = 1.f; - EXPECT_EQ(6, sFakeComposer->getFrameCount()); - EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); - - // trigger the second deferred transaction - fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY); - sFakeComposer->runVSyncAndWait(); - // TODO: Compute from layer size? - referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{128, 128, 128 + 64, 128 + 64}; - referenceFrame[SYNC_LAYER].mSwapCount++; - EXPECT_EQ(7, sFakeComposer->getFrameCount()); - EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame())); - } - void Test_SetRelativeLayer() { constexpr int RELATIVE_LAYER = 2; auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64, @@ -1625,10 +1553,6 @@ TEST_F(TransactionTest_2_1, DISABLED_LayerSetMatrix) { Test_LayerSetMatrix(); } -TEST_F(TransactionTest_2_1, DISABLED_DeferredTransaction) { - Test_DeferredTransaction(); -} - TEST_F(TransactionTest_2_1, DISABLED_SetRelativeLayer) { Test_SetRelativeLayer(); } @@ -1799,44 +1723,6 @@ protected: EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame())); } - void Test_Bug36858924() { - // Destroy the child layer - mChild.clear(); - - // Now recreate it as hidden - mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10, - PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eHidden, - Base::mFGSurfaceControl->getHandle()); - - // Show the child layer in a deferred transaction - { - TransactionScope ts(*Base::sFakeComposer); - ts.deferTransactionUntil_legacy(mChild, Base::mFGSurfaceControl, - Base::mFGSurfaceControl->getSurface() - ->getNextFrameNumber()); - ts.show(mChild); - } - - // Render the foreground surface a few times - // - // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the - // third frame because SurfaceFlinger would never process the deferred transaction and would - // therefore never acquire/release the first buffer - ALOGI("Filling 1"); - fillSurfaceRGBA8(Base::mFGSurfaceControl, GREEN); - Base::sFakeComposer->runVSyncAndWait(); - ALOGI("Filling 2"); - fillSurfaceRGBA8(Base::mFGSurfaceControl, BLUE); - Base::sFakeComposer->runVSyncAndWait(); - ALOGI("Filling 3"); - fillSurfaceRGBA8(Base::mFGSurfaceControl, RED); - Base::sFakeComposer->runVSyncAndWait(); - ALOGI("Filling 4"); - fillSurfaceRGBA8(Base::mFGSurfaceControl, GREEN); - Base::sFakeComposer->runVSyncAndWait(); - } - sp mChild; }; @@ -1867,10 +1753,6 @@ TEST_F(ChildLayerTest_2_1, DISABLED_ChildrenWithParentBufferTransform) { Test_ChildrenWithParentBufferTransform(); } -TEST_F(ChildLayerTest_2_1, DISABLED_Bug36858924) { - Test_Bug36858924(); -} - template class ChildColorLayerTest : public ChildLayerTest { using Base = ChildLayerTest; diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp index abecd4b45b..9c6ad06e1d 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp @@ -118,11 +118,8 @@ void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) { } void RefreshRateSelectionTest::commitTransaction(Layer* layer) { - layer->pushPendingState(); auto c = layer->getCurrentState(); - if (layer->applyPendingStates(&c)) { - layer->commitTransaction(c); - } + layer->commitTransaction(c); } void RefreshRateSelectionTest::setupScheduler() { diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 0bb7e31194..c088ddc971 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -153,11 +153,8 @@ void SetFrameRateTest::removeChild(sp layer, sp child) { void SetFrameRateTest::commitTransaction() { for (auto layer : mLayers) { - layer->pushPendingState(); auto c = layer->getCurrentState(); - if (layer->applyPendingStates(&c)) { - layer->commitTransaction(c); - } + layer->commitTransaction(c); } } diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index b5ef0a1334..ea1ce47b70 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -60,11 +60,8 @@ public: } void commitTransaction(Layer* layer) { - layer->pushPendingState(); auto c = layer->getCurrentState(); - if (layer->applyPendingStates(&c)) { - layer->commitTransaction(c); - } + layer->commitTransaction(c); } void setupScheduler() { @@ -151,4 +148,4 @@ TEST_F(TransactionFrameTracerTest, BLASTTransactionSendsFrameTracerEvents) { BLASTTransactionSendsFrameTracerEvents(); } -} // namespace android \ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index c75538f476..09a1c2af75 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -60,13 +60,8 @@ public: } void commitTransaction(Layer* layer) { - layer->pushPendingState(); - // After pushing the state, the currentState should not store any BufferlessSurfaceFrames - EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); auto c = layer->getCurrentState(); - if (layer->applyPendingStates(&c)) { - layer->commitTransaction(c); - } + layer->commitTransaction(c); } void setupScheduler() { @@ -283,69 +278,6 @@ public: EXPECT_EQ(PresentState::Presented, bufferSurfaceFrameTX->getPresentState()); } - void MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken() { - sp layer = createBufferStateLayer(); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 10); - EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); - ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); - const auto bufferlessSurfaceFrame1 = - layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1); - - layer->pushPendingState(); - EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); - - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2, /*inputEventId*/ 0}, - 12); - EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); - ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); - const auto bufferlessSurfaceFrame2 = - layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 2); - - commitTransaction(layer.get()); - - EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken()); - EXPECT_EQ(false, bufferlessSurfaceFrame1->getIsBuffer()); - EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame1->getPresentState()); - EXPECT_EQ(10, bufferlessSurfaceFrame1->getActuals().endTime); - - EXPECT_EQ(2, bufferlessSurfaceFrame2->getToken()); - EXPECT_EQ(false, bufferlessSurfaceFrame2->getIsBuffer()); - EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState()); - EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime); - } - - void MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken() { - sp layer = createBufferStateLayer(); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 10); - EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); - ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); - const auto bufferlessSurfaceFrame1 = - layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1); - - layer->pushPendingState(); - EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); - - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 12); - EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size()); - ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX); - const auto bufferlessSurfaceFrame2 = - layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1); - - commitTransaction(layer.get()); - - EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken()); - EXPECT_EQ(false, bufferlessSurfaceFrame1->getIsBuffer()); - EXPECT_EQ(PresentState::Unknown, bufferlessSurfaceFrame1->getPresentState()); - - EXPECT_EQ(1, bufferlessSurfaceFrame2->getToken()); - EXPECT_EQ(false, bufferlessSurfaceFrame2->getIsBuffer()); - EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState()); - EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime); - } - void PendingSurfaceFramesRemovedAfterClassification() { sp layer = createBufferStateLayer(); @@ -529,16 +461,6 @@ TEST_F(TransactionSurfaceFrameTest, MultipleSurfaceFramesPresentedTogether) { MultipleSurfaceFramesPresentedTogether(); } -TEST_F(TransactionSurfaceFrameTest, - MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken) { - MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken(); -} - -TEST_F(TransactionSurfaceFrameTest, - MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken) { - MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken(); -} - TEST_F(TransactionSurfaceFrameTest, PendingSurfaceFramesRemovedAfterClassification) { PendingSurfaceFramesRemovedAfterClassification(); } @@ -552,4 +474,4 @@ TEST_F(TransactionSurfaceFrameTest, MultipleCommitsBeforeLatch) { MultipleCommitsBeforeLatch(); } -} // namespace android \ No newline at end of file +} // namespace android -- 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/BufferLayer.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/BufferLayer.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/BufferLayer.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 a102ff9348cf71ed1fc938e6e1c9fd00963123a5 Mon Sep 17 00:00:00 2001 From: "yuhui.zhang" Date: Fri, 9 Apr 2021 14:45:51 +0800 Subject: Fix the secure flag check for blackout layer issue When there is a layer not to be composed on insecure virtual display, surfaceflinger will send a black color layer to render engine to compose instead of the original buffer. If render engine supports protected context, but layer does not set the eLayerSecure flag,the layer will not be set to black color layer and will be sent to render engine to compose on the insecure display based on current logic, even if the layer buffer usage is protected. Solution: add buffer usage check for insecure display case. Test result: The secure layer buffer will not be sent to render engine for the insecure virtual display to compose, and a black color layer will be sent instead. Bug: 185195873 Test: By partner Change-Id: Iad53411ea642fee3e5b09222760a223b4ada61ad --- services/surfaceflinger/BufferLayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index d243989a34..4c73b6edda 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -186,7 +186,7 @@ std::optional BufferLayer::prepareCli } } const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || - (isSecure() && !targetSettings.isSecure); + ((isSecure() || isProtected()) && !targetSettings.isSecure); const bool bufferCanBeUsedAsHwTexture = mBufferInfo.mBuffer->getBuffer()->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; compositionengine::LayerFE::LayerSettings& layer = *result; -- cgit v1.2.3-59-g8ed1b From ac09e45ab3aa3799ff071c8fe97ac4ebe5b9ae5c Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 7 Apr 2021 16:35:37 -0400 Subject: Make sdr white point do a thing Bug: 182312559 Test: SilkFX prototype changes Change-Id: Ieca0e4c8e2229d14aac460945702d23759d208e9 --- libs/renderengine/gl/GLESRenderEngine.cpp | 6 +++-- .../include/renderengine/DisplaySettings.h | 3 +++ .../include/renderengine/LayerSettings.h | 10 ++++---- libs/renderengine/skia/Cache.cpp | 6 ++--- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 14 +++++++---- libs/renderengine/skia/filters/LinearEffect.cpp | 8 ++++--- libs/renderengine/skia/filters/LinearEffect.h | 2 +- services/surfaceflinger/BufferLayer.cpp | 27 +++++++++++++++------- .../include/compositionengine/Output.h | 3 +++ .../include/compositionengine/impl/Output.h | 1 + .../impl/OutputCompositionState.h | 6 +++++ .../include/compositionengine/mock/Output.h | 1 + .../src/ClientCompositionRequestCache.cpp | 3 +-- .../CompositionEngine/src/Output.cpp | 21 +++++++++++++++-- services/surfaceflinger/SurfaceFlinger.cpp | 13 +++++++++-- services/surfaceflinger/SurfaceFlinger.h | 4 ++++ .../surfaceflinger/SurfaceFlingerProperties.cpp | 4 ++++ services/surfaceflinger/SurfaceFlingerProperties.h | 2 ++ .../sysprop/SurfaceFlingerProperties.sysprop | 9 ++++++++ .../api/SurfaceFlingerProperties-current.txt | 4 ++++ 20 files changed, 113 insertions(+), 34 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index d87315fdc2..b5510d97d4 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -1233,8 +1233,10 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, } } - mState.maxMasteringLuminance = layer->source.buffer.maxMasteringLuminance; - mState.maxContentLuminance = layer->source.buffer.maxContentLuminance; + // Ensure luminance is at least 100 nits to avoid div-by-zero + const float maxLuminance = std::max(100.f, layer->source.buffer.maxLuminanceNits); + mState.maxMasteringLuminance = maxLuminance; + mState.maxContentLuminance = maxLuminance; mState.projectionMatrix = projectionMatrix * layer->geometry.positionTransform; const FloatRect bounds = layer->geometry.boundaries; diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index a637796267..53fa622ad8 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -60,6 +60,9 @@ struct DisplaySettings { // capture of a device in landscape while the buffer is in portrait // orientation. uint32_t orientation = ui::Transform::ROT_0; + + // SDR white point, -1f if unknown + float sdrWhitePointNits = -1.f; }; static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) { diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index e976a5a7fc..993448ddb8 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -64,8 +64,8 @@ struct Buffer { // HDR color-space setting for Y410. bool isY410BT2020 = false; - float maxMasteringLuminance = 0.0; - float maxContentLuminance = 0.0; + + float maxLuminanceNits = 0.0; }; // Metadata describing the layer geometry. @@ -175,8 +175,7 @@ static inline bool operator==(const Buffer& lhs, const Buffer& rhs) { lhs.textureTransform == rhs.textureTransform && lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha && lhs.isOpaque == rhs.isOpaque && lhs.isY410BT2020 == rhs.isY410BT2020 && - lhs.maxMasteringLuminance == rhs.maxMasteringLuminance && - lhs.maxContentLuminance == rhs.maxContentLuminance; + lhs.maxLuminanceNits == rhs.maxLuminanceNits; } static inline bool operator==(const Geometry& lhs, const Geometry& rhs) { @@ -237,8 +236,7 @@ static inline void PrintTo(const Buffer& settings, ::std::ostream* os) { *os << "\n .usePremultipliedAlpha = " << settings.usePremultipliedAlpha; *os << "\n .isOpaque = " << settings.isOpaque; *os << "\n .isY410BT2020 = " << settings.isY410BT2020; - *os << "\n .maxMasteringLuminance = " << settings.maxMasteringLuminance; - *os << "\n .maxContentLuminance = " << settings.maxContentLuminance; + *os << "\n .maxLuminanceNits = " << settings.maxLuminanceNits; *os << "\n}"; } diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index 6ab93dfb4d..58d124a5c4 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -108,8 +108,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting .source = PixelSource{.buffer = Buffer{ .buffer = srcTexture, - .maxMasteringLuminance = 1000.f, - .maxContentLuminance = 1000.f, + .maxLuminanceNits = 1000.f, }}, }; @@ -205,8 +204,7 @@ static void drawTextureScaleLayers(SkiaRenderEngine* renderengine, const Display .source = PixelSource{.buffer = Buffer{ .buffer = srcTexture, - .maxMasteringLuminance = 1000.f, - .maxContentLuminance = 1000.f, + .maxLuminanceNits = 1000.f, .textureTransform = kScaleYOnly, }}, .sourceDataspace = kOtherDataSpace, diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index acdb78a212..160ffb3ee4 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -567,10 +567,14 @@ sk_sp SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp sh } else { runtimeEffect = effectIter->second; } + float maxLuminance = layer->source.buffer.maxLuminanceNits; + // If the buffer doesn't have a max luminance, treat it as SDR & use the display's SDR + // white point + if (maxLuminance <= 0.f) { + maxLuminance = display.sdrWhitePointNits; + } return createLinearEffectShader(shader, effect, runtimeEffect, layer->colorTransform, - display.maxLuminance, - layer->source.buffer.maxMasteringLuminance, - layer->source.buffer.maxContentLuminance); + display.maxLuminance, maxLuminance); } return shader; } @@ -866,7 +870,9 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, const bool requiresLinearEffect = layer->colorTransform != mat4() || (mUseColorManagement && - needsToneMapping(layer->sourceDataspace, display.outputDataspace)); + needsToneMapping(layer->sourceDataspace, display.outputDataspace)) || + (display.sdrWhitePointNits > 0.f && + display.sdrWhitePointNits != display.maxLuminance); // quick abort from drawing the remaining portion of the layer if (layer->alpha == 0 && !requiresLinearEffect && !layer->disableBlending && diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp index 0fbd6698d8..9b044e1685 100644 --- a/libs/renderengine/skia/filters/LinearEffect.cpp +++ b/libs/renderengine/skia/filters/LinearEffect.cpp @@ -127,7 +127,7 @@ static void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, SkStrin default: shader.append(R"( float3 ScaleLuminance(float3 xyz) { - return xyz * in_displayMaxLuminance; + return xyz * in_inputMaxLuminance; } )"); break; @@ -448,7 +448,7 @@ sk_sp buildRuntimeEffect(const LinearEffect& linearEffect) { sk_sp createLinearEffectShader(sk_sp shader, const LinearEffect& linearEffect, sk_sp runtimeEffect, const mat4& colorTransform, float maxDisplayLuminance, - float maxMasteringLuminance, float maxContentLuminance) { + float maxLuminance) { ATRACE_CALL(); SkRuntimeShaderBuilder effectBuilder(runtimeEffect); @@ -467,8 +467,10 @@ sk_sp createLinearEffectShader(sk_sp shader, const LinearEff } effectBuilder.uniform("in_displayMaxLuminance") = maxDisplayLuminance; + // If the input luminance is unknown, use display luminance (aka, no-op any luminance changes) + // This will be the case for eg screenshots in addition to uncalibrated displays effectBuilder.uniform("in_inputMaxLuminance") = - std::min(maxMasteringLuminance, maxContentLuminance); + maxLuminance > 0 ? maxLuminance : maxDisplayLuminance; return effectBuilder.makeShader(nullptr, false); } diff --git a/libs/renderengine/skia/filters/LinearEffect.h b/libs/renderengine/skia/filters/LinearEffect.h index 20b8338931..9e989eae27 100644 --- a/libs/renderengine/skia/filters/LinearEffect.h +++ b/libs/renderengine/skia/filters/LinearEffect.h @@ -98,7 +98,7 @@ sk_sp createLinearEffectShader(sk_sp inputShader, const LinearEffect& linearEffect, sk_sp runtimeEffect, const mat4& colorTransform, float maxDisplayLuminance, - float maxMasteringLuminance, float maxContentLuminance); + float maxLuminance); } // namespace skia } // namespace renderengine } // namespace android diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 4c73b6edda..cacad52410 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -58,8 +58,7 @@ namespace android { -static constexpr float defaultMaxMasteringLuminance = 1000.0; -static constexpr float defaultMaxContentLuminance = 1000.0; +static constexpr float defaultMaxLuminance = 1000.0; BufferLayer::BufferLayer(const LayerCreationArgs& args) : Layer(args), @@ -206,12 +205,24 @@ std::optional BufferLayer::prepareCli layer.source.buffer.isY410BT2020 = isHdrY410(); bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086; bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3; - layer.source.buffer.maxMasteringLuminance = hasSmpte2086 - ? mBufferInfo.mHdrMetadata.smpte2086.maxLuminance - : defaultMaxMasteringLuminance; - layer.source.buffer.maxContentLuminance = hasCta861_3 - ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel - : defaultMaxContentLuminance; + float maxLuminance = 0.f; + if (hasSmpte2086 && hasCta861_3) { + maxLuminance = std::min(mBufferInfo.mHdrMetadata.smpte2086.maxLuminance, + mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel); + } else if (hasSmpte2086) { + maxLuminance = mBufferInfo.mHdrMetadata.smpte2086.maxLuminance; + } else if (hasCta861_3) { + maxLuminance = mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel; + } else { + switch (layer.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + case HAL_DATASPACE_TRANSFER_HLG: + // Behavior-match previous releases for HDR content + maxLuminance = defaultMaxLuminance; + break; + } + } + layer.source.buffer.maxLuminanceNits = maxLuminance; layer.frameNumber = mCurrentFrameNumber; layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer()->getId() : 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 497621397c..af5824562b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -181,6 +181,9 @@ public: // Sets the output color mode virtual void setColorProfile(const ColorProfile&) = 0; + // Sets current calibrated display brightness information + virtual void setDisplayBrightness(float sdrWhitePointNits, float displayBrightnessNits) = 0; + // Outputs a string with a state dump virtual void dump(std::string&) const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index eeb20fc1d1..07eaaefd06 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -51,6 +51,7 @@ public: void setColorTransform(const compositionengine::CompositionRefreshArgs&) override; void setColorProfile(const ColorProfile&) override; + void setDisplayBrightness(float sdrWhitePointNits, float displayBrightnessNits) override; void dump(std::string&) const override; void dumpPlannerInfo(const Vector& args, std::string&) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index f0ef6d6e7d..d41c2dd527 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -118,6 +118,12 @@ struct OutputCompositionState { // The earliest time to send the present command to the HAL std::chrono::steady_clock::time_point earliestPresentTime; + // Current display brightness + float displayBrightnessNits{-1.f}; + + // SDR white point + float sdrWhitePointNits{-1.f}; + // Debugging void dump(std::string& result) const; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 5aa53e54dd..49d93ca5d6 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -43,6 +43,7 @@ public: MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD1(setColorProfile, void(const ColorProfile&)); + MOCK_METHOD2(setDisplayBrightness, void(float, float)); MOCK_CONST_METHOD1(dump, void(std::string&)); MOCK_CONST_METHOD2(dumpPlannerInfo, void(const Vector&, std::string&)); diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp index 2d9f01b9fd..27b0c808ff 100644 --- a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp +++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp @@ -45,8 +45,7 @@ inline bool equalIgnoringBuffer(const renderengine::Buffer& lhs, const rendereng lhs.textureTransform == rhs.textureTransform && lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha && lhs.isOpaque == rhs.isOpaque && lhs.isY410BT2020 == rhs.isY410BT2020 && - lhs.maxMasteringLuminance == rhs.maxMasteringLuminance && - lhs.maxContentLuminance == rhs.maxContentLuminance; + lhs.maxLuminanceNits == rhs.maxLuminanceNits; } inline bool equalIgnoringBuffer(const renderengine::LayerSettings& lhs, diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index c809e1afad..6c2f9c515c 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -256,6 +256,18 @@ void Output::setColorProfile(const ColorProfile& colorProfile) { dirtyEntireOutput(); } +void Output::setDisplayBrightness(float sdrWhitePointNits, float displayBrightnessNits) { + auto& outputState = editState(); + if (outputState.sdrWhitePointNits == sdrWhitePointNits && + outputState.displayBrightnessNits == displayBrightnessNits) { + // Nothing changed + return; + } + outputState.sdrWhitePointNits = sdrWhitePointNits; + outputState.displayBrightnessNits = displayBrightnessNits; + dirtyEntireOutput(); +} + void Output::dump(std::string& out) const { using android::base::StringAppendF; @@ -1032,8 +1044,13 @@ std::optional Output::composeSurfaces( clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut() ? outputState.dataspace : ui::Dataspace::UNKNOWN; - clientCompositionDisplay.maxLuminance = - mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance(); + + // If we have a valid current display brightness use that, otherwise fall back to the + // display's max desired + clientCompositionDisplay.maxLuminance = outputState.displayBrightnessNits > 0.f + ? outputState.displayBrightnessNits + : mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance(); + clientCompositionDisplay.sdrWhitePointNits = outputState.sdrWhitePointNits; // Compute the global color transform matrix. if (!outputState.usesDeviceComposition && !getSkipColorTransform()) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2dace92eaa..6f830aaf83 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -306,6 +306,7 @@ ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat: Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB; ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; bool SurfaceFlinger::useFrameRateApi; +bool SurfaceFlinger::enableSdrDimming; std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { switch(displayColorSetting) { @@ -471,6 +472,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI base::SetProperty(KERNEL_IDLE_TIMER_PROP, mKernelIdleTimerEnabled ? "true" : "false"); mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0); + + // Debug property overrides ro. property + enableSdrDimming = property_get_bool("debug.sf.enable_sdr_dimming", enable_sdr_dimming(false)); } SurfaceFlinger::~SurfaceFlinger() = default; @@ -1480,8 +1484,13 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, } return ftl::chain(schedule([=]() MAIN_THREAD { - if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { - return getHwComposer().setDisplayBrightness(*displayId, + if (const auto display = getDisplayDeviceLocked(displayToken)) { + if (enableSdrDimming) { + display->getCompositionDisplay() + ->setDisplayBrightness(brightness.sdrWhitePointNits, + brightness.displayBrightnessNits); + } + return getHwComposer().setDisplayBrightness(display->getPhysicalId(), brightness.displayBrightness); } else { ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index cf1a545342..8523b1ab1a 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -271,6 +271,10 @@ public: static constexpr SkipInitializationTag SkipInitialization; + // Whether or not SDR layers should be dimmed to the desired SDR white point instead of + // being treated as native display brightness + static bool enableSdrDimming; + // must be called before clients can connect void init() ANDROID_API; diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index b3dca789e2..4a69c8f0c3 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -321,6 +321,10 @@ bool use_frame_rate_api(bool defaultValue) { return defaultValue; } +bool enable_sdr_dimming(bool defaultValue) { + return SurfaceFlingerProperties::enable_sdr_dimming().value_or(defaultValue); +} + int32_t display_update_imminent_timeout_ms(int32_t defaultValue) { auto temp = SurfaceFlingerProperties::display_update_imminent_timeout_ms(); if (temp.has_value()) { diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index b19d216268..039d316a95 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -102,6 +102,8 @@ bool enable_frame_rate_override(bool defaultValue); bool enable_layer_caching(bool defaultValue); +bool enable_sdr_dimming(bool defaultValue); + } // namespace sysprop } // namespace android #endif // SURFACEFLINGERPROPERTIES_H_ diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index ee5542d628..78f8a2f0ae 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -463,3 +463,12 @@ prop { access: Readonly prop_name: "ro.surface_flinger.enable_layer_caching" } + +# Enables SDR layer dimming +prop { + api_name: "enable_sdr_dimming" + type: Boolean + scope: Public + access: Readonly + prop_name: "ro.surface_flinger.enable_sdr_dimming" +} \ No newline at end of file diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt index 47e14f656b..9c567d6afa 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -52,6 +52,10 @@ props { api_name: "enable_protected_contents" prop_name: "ro.surface_flinger.protected_contents" } + prop { + api_name: "enable_sdr_dimming" + prop_name: "ro.surface_flinger.enable_sdr_dimming" + } prop { api_name: "force_hwc_copy_for_virtual_displays" prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays" -- cgit v1.2.3-59-g8ed1b From 58069dcb4718032f891d6d17745b519d1af8e27a Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan Date: Fri, 4 Jun 2021 20:37:02 +0000 Subject: SF - plumbing game mode for metrics (part 2) Update TimeStats to take in the game mode from layer for all the frames. Bug: 186025682 Test: statsd_testdrive 10063 Test: atest libsurfaceflinger_unittest Change-Id: If95a8c91940228a8925ae9e4e21656d1b492a2ba --- services/surfaceflinger/BufferLayer.cpp | 6 +- services/surfaceflinger/BufferStateLayer.cpp | 2 +- .../surfaceflinger/FrameTimeline/FrameTimeline.cpp | 17 +- .../surfaceflinger/FrameTimeline/FrameTimeline.h | 10 +- services/surfaceflinger/Layer.cpp | 7 +- services/surfaceflinger/Layer.h | 8 +- services/surfaceflinger/TimeStats/TimeStats.cpp | 50 +++-- services/surfaceflinger/TimeStats/TimeStats.h | 23 +- .../timestatsatomsproto/timestats_atoms.proto | 19 +- .../TimeStats/timestatsproto/TimeStatsHelper.cpp | 15 ++ .../include/timestatsproto/TimeStatsHelper.h | 31 ++- .../tests/unittests/FrameTimelineTest.cpp | 161 ++++++------- .../tests/unittests/TimeStatsTest.cpp | 248 +++++++++++++++------ .../tests/unittests/mock/MockTimeStats.h | 11 +- 14 files changed, 398 insertions(+), 210 deletions(-) (limited to 'services/surfaceflinger/BufferLayer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index cacad52410..23779be73a 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -425,7 +425,8 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence, refreshRate, renderRate, frameRateToSetFrameRateVotePayload( - mDrawingState.frameRate)); + mDrawingState.frameRate), + getGameMode()); mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, presentFence, FrameTracer::FrameEvent::PRESENT_FENCE); mFrameTracker.setActualPresentFence(std::shared_ptr(presentFence)); @@ -439,7 +440,8 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display, mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime, refreshRate, renderRate, frameRateToSetFrameRateVotePayload( - mDrawingState.frameRate)); + mDrawingState.frameRate), + getGameMode()); mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, actualPresentTime, FrameTracer::FrameEvent::PRESENT_FENCE); diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 54daa102ba..5298772956 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -444,7 +444,7 @@ bool BufferStateLayer::setBuffer(const std::shared_ptrmTimeStats->setPostTime(layerId, mCurrentState.frameNumber, getName().c_str(), - mOwnerUid, postTime); + mOwnerUid, postTime, getGameMode()); mCurrentState.desiredPresentTime = desiredPresentTime; mCurrentState.isAutoTimestamp = isAutoTimestamp; diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 9b03287242..3523b565dc 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -304,7 +304,7 @@ SurfaceFrame::SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t own frametimeline::TimelineItem&& predictions, std::shared_ptr timeStats, JankClassificationThresholds thresholds, - TraceCookieCounter* traceCookieCounter, bool isBuffer) + TraceCookieCounter* traceCookieCounter, bool isBuffer, int32_t gameMode) : mToken(frameTimelineInfo.vsyncId), mInputEventId(frameTimelineInfo.inputEventId), mOwnerPid(ownerPid), @@ -319,7 +319,8 @@ SurfaceFrame::SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t own mTimeStats(timeStats), mJankClassificationThresholds(thresholds), mTraceCookieCounter(*traceCookieCounter), - mIsBuffer(isBuffer) {} + mIsBuffer(isBuffer), + mGameMode(gameMode) {} void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) { std::scoped_lock lock(mMutex); @@ -607,8 +608,8 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, if (mPredictionState != PredictionState::None) { // Only update janky frames if the app used vsync predictions mTimeStats->incrementJankyFrames({refreshRate, mRenderRate, mOwnerUid, mLayerName, - mJankType, displayDeadlineDelta, displayPresentDelta, - deadlineDelta}); + mGameMode, mJankType, displayDeadlineDelta, + displayPresentDelta, deadlineDelta}); } } @@ -776,14 +777,14 @@ void FrameTimeline::registerDataSource() { std::shared_ptr FrameTimeline::createSurfaceFrameForToken( const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, int32_t layerId, - std::string layerName, std::string debugName, bool isBuffer) { + std::string layerName, std::string debugName, bool isBuffer, int32_t gameMode) { ATRACE_CALL(); if (frameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { return std::make_shared(frameTimelineInfo, ownerPid, ownerUid, layerId, std::move(layerName), std::move(debugName), PredictionState::None, TimelineItem(), mTimeStats, mJankClassificationThresholds, &mTraceCookieCounter, - isBuffer); + isBuffer, gameMode); } std::optional predictions = mTokenManager.getPredictionsForToken(frameTimelineInfo.vsyncId); @@ -792,13 +793,13 @@ std::shared_ptr FrameTimeline::createSurfaceFrameForToken( std::move(layerName), std::move(debugName), PredictionState::Valid, std::move(*predictions), mTimeStats, mJankClassificationThresholds, - &mTraceCookieCounter, isBuffer); + &mTraceCookieCounter, isBuffer, gameMode); } return std::make_shared(frameTimelineInfo, ownerPid, ownerUid, layerId, std::move(layerName), std::move(debugName), PredictionState::Expired, TimelineItem(), mTimeStats, mJankClassificationThresholds, &mTraceCookieCounter, - isBuffer); + isBuffer, gameMode); } FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr timeStats, diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index 42be55ae2c..15ecf130e7 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -154,7 +154,7 @@ public: int32_t layerId, std::string layerName, std::string debugName, PredictionState predictionState, TimelineItem&& predictions, std::shared_ptr timeStats, JankClassificationThresholds thresholds, - TraceCookieCounter* traceCookieCounter, bool isBuffer); + TraceCookieCounter* traceCookieCounter, bool isBuffer, int32_t gameMode); ~SurfaceFrame() = default; // Returns std::nullopt if the frame hasn't been classified yet. @@ -259,6 +259,8 @@ private: // Tells if the SurfaceFrame is representing a buffer or a transaction without a // buffer(animations) bool mIsBuffer; + // GameMode from the layer. Used in metrics. + int32_t mGameMode = 0; }; /* @@ -278,7 +280,8 @@ public: // Debug name is the human-readable debugging string for dumpsys. virtual std::shared_ptr createSurfaceFrameForToken( const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, - int32_t layerId, std::string layerName, std::string debugName, bool isBuffer) = 0; + int32_t layerId, std::string layerName, std::string debugName, bool isBuffer, + int32_t gameMode) = 0; // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be // composited into one display frame. @@ -437,7 +440,8 @@ public: frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; } std::shared_ptr createSurfaceFrameForToken( const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, - int32_t layerId, std::string layerName, std::string debugName, bool isBuffer) override; + int32_t layerId, std::string layerName, std::string debugName, bool isBuffer, + int32_t gameMode) override; void addSurfaceFrame(std::shared_ptr surfaceFrame) override; void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override; void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr& presentFence, diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 9fcc17c4b4..e50087f819 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1357,7 +1357,7 @@ std::shared_ptr Layer::createSurfaceFrameForTransac mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, getSequence(), mName, mTransactionName, - /*isBuffer*/ false); + /*isBuffer*/ false, getGameMode()); // For Transactions, the post time is considered to be both queue and acquire fence time. surfaceFrame->setActualQueueTime(postTime); surfaceFrame->setAcquireFenceTime(postTime); @@ -1374,7 +1374,7 @@ std::shared_ptr Layer::createSurfaceFrameForBuffer( auto surfaceFrame = mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, getSequence(), mName, debugName, - /*isBuffer*/ true); + /*isBuffer*/ true, getGameMode()); // For buffers, acquire fence time will set during latch. surfaceFrame->setActualQueueTime(queueTime); const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); @@ -1635,7 +1635,8 @@ void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, FrameEventHistoryDelta* outDelta) { if (newTimestamps) { mFlinger->mTimeStats->setPostTime(getSequence(), newTimestamps->frameNumber, - getName().c_str(), mOwnerUid, newTimestamps->postedTime); + getName().c_str(), mOwnerUid, newTimestamps->postedTime, + getGameMode()); mFlinger->mTimeStats->setAcquireFence(getSequence(), newTimestamps->frameNumber, newTimestamps->acquireFence); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index af2604582b..dde0031201 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -850,9 +850,9 @@ public: // Sets the parent's gameMode for this layer and all its children. Parent's gameMode is applied // only to layers that do not have the GAME_MODE_METADATA set by WMShell. Any layer(along with // its children) that has the metadata set will use the gameMode from the metadata. - void setGameModeForTree(int parentGameMode); - void setGameMode(int gameMode) { mGameMode = gameMode; }; - int getGameMode() const { return mGameMode; } + void setGameModeForTree(int32_t parentGameMode); + void setGameMode(int32_t gameMode) { mGameMode = gameMode; }; + int32_t getGameMode() const { return mGameMode; } virtual uid_t getOwnerUid() const { return mOwnerUid; } @@ -1098,7 +1098,7 @@ private: // Game mode for the layer. Set by WindowManagerShell, game mode is used in // metrics(SurfaceFlingerStats). - int mGameMode = 0; + int32_t mGameMode = 0; // A list of regions on this layer that should have blurs. const std::vector getBlurRegions() const; diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index d6a0787ddc..f1b153fe7e 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -58,6 +58,21 @@ FrameTimingHistogram histogramToProto(const std::unordered_map return histogramProto; } +SurfaceflingerStatsLayerInfo_GameMode gameModeToProto(int32_t gameMode) { + switch (gameMode) { + case TimeStatsHelper::GameModeUnsupported: + return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSUPPORTED; + case TimeStatsHelper::GameModeStandard: + return SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD; + case TimeStatsHelper::GameModePerformance: + return SurfaceflingerStatsLayerInfo::GAME_MODE_PERFORMANCE; + case TimeStatsHelper::GameModeBattery: + return SurfaceflingerStatsLayerInfo::GAME_MODE_BATTERY; + default: + return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSPECIFIED; + } +} + SurfaceflingerStatsLayerInfo_SetFrameRateVote frameRateVoteToProto( const TimeStats::SetFrameRateVote& setFrameRateVote) { using FrameRateCompatibilityEnum = @@ -206,6 +221,7 @@ bool TimeStats::populateLayerAtom(std::string* pulledData) { *atom->mutable_app_deadline_misses() = histogramToProto(layer->deltas["appDeadlineDeltas"].hist, mMaxPulledHistogramBuckets); + atom->set_game_mode(gameModeToProto(layer->gameMode)); } // Always clear data. @@ -437,7 +453,8 @@ static int32_t clampToNearestBucket(Fps fps, size_t bucketWidth) { void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote) { + SetFrameRateVote frameRateVote, + int32_t gameMode) { ATRACE_CALL(); ALOGV("[%d]-flushAvailableRecordsToStatsLocked", layerId); @@ -464,12 +481,13 @@ void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayR TimeStatsHelper::TimelineStats& displayStats = mTimeStats.stats[timelineKey]; - TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName}; + TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName, gameMode}; if (!displayStats.stats.count(layerKey)) { displayStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket; displayStats.stats[layerKey].renderRateBucket = renderRateBucket; displayStats.stats[layerKey].uid = uid; displayStats.stats[layerKey].layerName = layerName; + displayStats.stats[layerKey].gameMode = gameMode; } if (frameRateVote.frameRate > 0.0f) { displayStats.stats[layerKey].setFrameRateVote = frameRateVote; @@ -535,10 +553,11 @@ static bool layerNameIsValid(const std::string& layerName) { layerName.compare(0, kMinLenLayerName, kPopupWindowPrefix) != 0; } -bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName) { +bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName, + int32_t gameMode) { uint32_t layerRecords = 0; for (const auto& record : mTimeStats.stats) { - if (record.second.stats.count({uid, layerName}) > 0) { + if (record.second.stats.count({uid, layerName, gameMode}) > 0) { return true; } @@ -549,7 +568,7 @@ bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName } void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, - uid_t uid, nsecs_t postTime) { + uid_t uid, nsecs_t postTime, int32_t gameMode) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -557,13 +576,14 @@ void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::st postTime); std::lock_guard lock(mMutex); - if (!canAddNewAggregatedStats(uid, layerName)) { + if (!canAddNewAggregatedStats(uid, layerName, gameMode)) { return; } if (!mTimeStatsTracker.count(layerId) && mTimeStatsTracker.size() < MAX_NUM_LAYER_RECORDS && layerNameIsValid(layerName)) { mTimeStatsTracker[layerId].uid = uid; mTimeStatsTracker[layerId].layerName = layerName; + mTimeStatsTracker[layerId].gameMode = gameMode; } if (!mTimeStatsTracker.count(layerId)) return; LayerRecord& layerRecord = mTimeStatsTracker[layerId]; @@ -698,7 +718,7 @@ void TimeStats::setAcquireFence(int32_t layerId, uint64_t frameNumber, void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote) { + SetFrameRateVote frameRateVote, int32_t gameMode) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -717,13 +737,14 @@ void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t pr layerRecord.waitData++; } - flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote); + flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote, + gameMode); } void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& presentFence, Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote) { + SetFrameRateVote frameRateVote, int32_t gameMode) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -743,7 +764,8 @@ void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, layerRecord.waitData++; } - flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote); + flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote, + gameMode); } static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL | @@ -801,6 +823,7 @@ void TimeStats::incrementJankyFrames(const JankyFramesInfo& info) { // the first jank record is not dropped. static const std::string kDefaultLayerName = "none"; + static constexpr int32_t kDefaultGameMode = TimeStatsHelper::GameModeUnsupported; const int32_t refreshRateBucket = clampToNearestBucket(info.refreshRate, REFRESH_RATE_BUCKET_WIDTH); @@ -817,13 +840,14 @@ void TimeStats::incrementJankyFrames(const JankyFramesInfo& info) { updateJankPayload(timelineStats, info.reasons); - TimeStatsHelper::LayerStatsKey layerKey = {info.uid, info.layerName}; + TimeStatsHelper::LayerStatsKey layerKey = {info.uid, info.layerName, info.gameMode}; if (!timelineStats.stats.count(layerKey)) { - layerKey = {info.uid, kDefaultLayerName}; + layerKey = {info.uid, kDefaultLayerName, kDefaultGameMode}; timelineStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket; timelineStats.stats[layerKey].renderRateBucket = renderRateBucket; timelineStats.stats[layerKey].uid = info.uid; - timelineStats.stats[layerKey].layerName = kDefaultLayerName; + timelineStats.stats[layerKey].layerName = kDefaultGameMode; + timelineStats.stats[layerKey].gameMode = info.gameMode; } TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timelineStats.stats[layerKey]; diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 5b0f5bd13d..dd48950fd0 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -87,7 +87,7 @@ public: const std::shared_ptr& readyFence) = 0; virtual void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, - uid_t uid, nsecs_t postTime) = 0; + uid_t uid, nsecs_t postTime, int32_t gameMode) = 0; virtual void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) = 0; // Reasons why latching a particular buffer may be skipped enum class LatchSkipReason { @@ -109,11 +109,11 @@ public: // rendering path, as they flush prior fences if those fences have fired. virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote) = 0; + SetFrameRateVote frameRateVote, int32_t gameMode) = 0; virtual void setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& presentFence, Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote) = 0; + SetFrameRateVote frameRateVote, int32_t gameMode) = 0; // Increments janky frames, blamed to the provided {refreshRate, renderRate, uid, layerName} // key, with JankMetadata as supplementary reasons for the jank. Because FrameTimeline is the @@ -131,6 +131,7 @@ public: std::optional renderRate; uid_t uid = 0; std::string layerName; + int32_t gameMode = 0; int32_t reasons = 0; nsecs_t displayDeadlineDelta = 0; nsecs_t displayPresentJitter = 0; @@ -141,8 +142,8 @@ public: ((renderRate == std::nullopt && o.renderRate == std::nullopt) || (renderRate != std::nullopt && o.renderRate != std::nullopt && Fps::EqualsInBuckets{}(*renderRate, *o.renderRate))) && - uid == o.uid && layerName == o.layerName && reasons == o.reasons && - displayDeadlineDelta == o.displayDeadlineDelta && + uid == o.uid && layerName == o.layerName && gameMode == o.gameMode && + reasons == o.reasons && displayDeadlineDelta == o.displayDeadlineDelta && displayPresentJitter == o.displayPresentJitter && appDeadlineDelta == o.appDeadlineDelta; } @@ -199,6 +200,7 @@ class TimeStats : public android::TimeStats { struct LayerRecord { uid_t uid; std::string layerName; + int32_t gameMode = 0; // This is the index in timeRecords, at which the timestamps for that // specific frame are still not fully received. This is not waiting for // fences to signal, but rather waiting to receive those fences/timestamps. @@ -251,7 +253,7 @@ public: const std::shared_ptr& readyFence) override; void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, uid_t uid, - nsecs_t postTime) override; + nsecs_t postTime, int32_t gameMode) override; void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) override; void incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) override; void incrementBadDesiredPresent(int32_t layerId) override; @@ -261,10 +263,11 @@ public: const std::shared_ptr& acquireFence) override; void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime, Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote) override; + SetFrameRateVote frameRateVote, int32_t gameMode) override; void setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& presentFence, Fps displayRefreshRate, - std::optional renderRate, SetFrameRateVote frameRateVote) override; + std::optional renderRate, SetFrameRateVote frameRateVote, + int32_t gameMode) override; void incrementJankyFrames(const JankyFramesInfo& info) override; // Clean up the layer record @@ -286,10 +289,10 @@ private: bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord); void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote); + SetFrameRateVote frameRateVote, int32_t gameMode); void flushPowerTimeLocked(); void flushAvailableGlobalRecordsToStatsLocked(); - bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName); + bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName, int32_t gameMode); void enable(); void disable(); diff --git a/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto b/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto index 133a5419b5..e45757ddfd 100644 --- a/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto +++ b/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto @@ -166,6 +166,23 @@ message SurfaceflingerStatsLayerInfo { // This is intended to be used as a dimension in collecting per-render rate // jank statistics. optional int32 render_rate_bucket = 23; + + enum GameMode { + GAME_MODE_UNSPECIFIED = 0; + GAME_MODE_UNSUPPORTED = 1; + GAME_MODE_STANDARD = 2; + GAME_MODE_PERFORMANCE = 3; + GAME_MODE_BATTERY = 4; + } + + // Game mode that the layer was running at. Used to track user engagement + // in different modes. The modes are defined in GameManager.java + // Game modes are used only for integrating with GameManager. All non-game + // layers will have this field set to UNSUPPORTED. + // Introduced in Android 12 + // This is intended to be used as a dimension in collecting per-game mode + // fps and frame related metrics. + optional GameMode game_mode = 26; // The layer for this set of metrics // In many scenarios the package name is included in the layer name, e.g., // layers created by Window Manager. But this is not a guarantee - in the @@ -271,7 +288,7 @@ message SurfaceflingerStatsLayerInfo { // Introduced in Android 12. optional FrameTimingHistogram app_deadline_misses = 25; - // Next ID: 26 + // Next ID: 27 } /** diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp index a7e7db25d7..ffb2f0921d 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp +++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp @@ -122,6 +122,20 @@ std::string TimeStatsHelper::SetFrameRateVote::toString() const { return result; } +std::string TimeStatsHelper::TimeStatsLayer::toString(int32_t gameMode) const { + switch (gameMode) { + case TimeStatsHelper::GameModeUnsupported: + return "GameModeUnsupported"; + case TimeStatsHelper::GameModeStandard: + return "GameModeStandard"; + case TimeStatsHelper::GameModePerformance: + return "GameModePerformance"; + case TimeStatsHelper::GameModeBattery: + return "GameModeBattery"; + default: + return "GameModeUnspecified"; + } +} std::string TimeStatsHelper::TimeStatsLayer::toString() const { std::string result = "\n"; StringAppendF(&result, "displayRefreshRate = %d fps\n", displayRefreshRateBucket); @@ -129,6 +143,7 @@ std::string TimeStatsHelper::TimeStatsLayer::toString() const { StringAppendF(&result, "uid = %d\n", uid); StringAppendF(&result, "layerName = %s\n", layerName.c_str()); StringAppendF(&result, "packageName = %s\n", packageName.c_str()); + StringAppendF(&result, "gameMode = %s\n", toString(gameMode).c_str()); StringAppendF(&result, "totalFrames = %d\n", totalFrames); StringAppendF(&result, "droppedFrames = %d\n", droppedFrames); StringAppendF(&result, "lateAcquireFrames = %d\n", lateAcquireFrames); diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h index 2b37ffef30..2afff8d313 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h +++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h @@ -77,6 +77,18 @@ public: std::string toString() const; }; + /** + * GameMode of the layer. GameModes are set by SysUI through WMShell. + * Actual game mode definitions are managed by GameManager.java + * The values defined here should always be in sync with the ones in GameManager. + */ + enum GameMode { + GameModeUnsupported = 0, + GameModeStandard = 1, + GameModePerformance = 2, + GameModeBattery = 3, + }; + class TimeStatsLayer { public: uid_t uid; @@ -84,6 +96,7 @@ public: std::string packageName; int32_t displayRefreshRateBucket = 0; int32_t renderRateBucket = 0; + int32_t gameMode = 0; int32_t totalFrames = 0; int32_t droppedFrames = 0; int32_t lateAcquireFrames = 0; @@ -93,6 +106,7 @@ public: std::unordered_map deltas; std::string toString() const; + std::string toString(int32_t gameMode) const; SFTimeStatsLayerProto toProto() const; }; @@ -123,24 +137,19 @@ public: struct LayerStatsKey { uid_t uid = 0; std::string layerName; + int32_t gameMode = 0; struct Hasher { size_t operator()(const LayerStatsKey& key) const { - size_t result = std::hash{}(key.uid); - return HashCombine(result, std::hash{}(key.layerName)); + size_t uidHash = std::hash{}(key.uid); + size_t layerNameHash = std::hash{}(key.layerName); + size_t gameModeHash = std::hash{}(key.gameMode); + return HashCombine(uidHash, HashCombine(layerNameHash, gameModeHash)); } }; bool operator==(const LayerStatsKey& o) const { - return uid == o.uid && layerName == o.layerName; - } - }; - - struct LayerStatsHasher { - size_t operator()(const std::pair& p) const { - // Normally this isn't a very good hash function due to symmetry reasons, - // but these are distinct types so this should be good enough - return std::hash{}(p.first) ^ std::hash{}(p.second); + return uid == o.uid && layerName == o.layerName && gameMode == o.gameMode; } }; diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index c6a41159c1..71a567a23f 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -175,6 +175,7 @@ static constexpr pid_t sPidTwo = 20; static constexpr int32_t sInputEventId = 5; static constexpr int32_t sLayerIdOne = 1; static constexpr int32_t sLayerIdTwo = 2; +static constexpr int32_t sGameMode = 0; TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); @@ -194,11 +195,11 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_getOwnerPidReturnsCorrectPi auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({}, sPidTwo, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); EXPECT_EQ(surfaceFrame1->getOwnerPid(), sPidOne); EXPECT_EQ(surfaceFrame2->getOwnerPid(), sPidTwo); } @@ -207,7 +208,7 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::None); } @@ -217,7 +218,7 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Expired); } @@ -227,7 +228,7 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validToken) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Valid); EXPECT_EQ(compareTimelineItems(surfaceFrame->getPredictions(), TimelineItem(10, 20, 30)), true); @@ -239,7 +240,7 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validInputEventId) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({token1, inputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); EXPECT_EQ(inputEventId, surfaceFrame->getInputEventId()); } @@ -250,7 +251,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); // Set up the display frame mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11)); @@ -278,11 +279,11 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdTwo, sLayerNameTwo, - sLayerNameTwo, /*isBuffer*/ true); + sLayerNameTwo, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -325,7 +326,7 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -347,7 +348,7 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -361,20 +362,20 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { } TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceAfterQueue) { - auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, sLayerIdOne, - "acquireFenceAfterQueue", - "acquireFenceAfterQueue", /*isBuffer*/ true); + auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, sLayerIdOne, + "acquireFenceAfterQueue", + "acquireFenceAfterQueue", + /*isBuffer*/ true, sGameMode); surfaceFrame->setActualQueueTime(123); surfaceFrame->setAcquireFenceTime(456); EXPECT_EQ(surfaceFrame->getActuals().endTime, 456); } TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceBeforeQueue) { - auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, sLayerIdOne, - "acquireFenceAfterQueue", - "acquireFenceAfterQueue", /*isBuffer*/ true); + auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, sLayerIdOne, + "acquireFenceAfterQueue", + "acquireFenceAfterQueue", + /*isBuffer*/ true, sGameMode); surfaceFrame->setActualQueueTime(456); surfaceFrame->setAcquireFenceTime(123); EXPECT_EQ(surfaceFrame->getActuals().endTime, 456); @@ -389,7 +390,7 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -406,7 +407,7 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -423,7 +424,7 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -443,7 +444,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_invalidSignalTime) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -471,7 +472,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_doesNotReportForInvalidTokens) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -486,7 +487,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, + sLayerNameOne, sGameMode, JankType::SurfaceFlingerCpuDeadlineMissed, 2, 10, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -496,7 +497,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -511,7 +512,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfGpu) { EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, + sLayerNameOne, sGameMode, JankType::SurfaceFlingerGpuDeadlineMissed, 4, 10, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -522,7 +523,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfGpu) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -537,8 +538,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { Fps refreshRate = Fps::fromPeriodNsecs(30); EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, JankType::DisplayHAL, - -4, 0, 0})); + sLayerNameOne, sGameMode, + JankType::DisplayHAL, -4, 0, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); @@ -547,7 +548,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); surfaceFrame1->setAcquireFenceTime(20); @@ -561,7 +562,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { Fps refreshRate = Fps(11.0); EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, + sLayerNameOne, sGameMode, JankType::AppDeadlineMissed, -4, 0, 25})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -571,7 +572,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -587,7 +588,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) { Fps refreshRate = Fps::fromPeriodNsecs(32); EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, + sLayerNameOne, sGameMode, JankType::SurfaceFlingerScheduling, -4, 0, -10})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -597,7 +598,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -613,7 +614,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) { Fps refreshRate = Fps::fromPeriodNsecs(16); EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, + sLayerNameOne, sGameMode, JankType::PredictionError, -4, 5, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -623,7 +624,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -639,7 +640,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) { Fps refreshRate = Fps::fromPeriodNsecs(32); EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, - sLayerNameOne, + sLayerNameOne, sGameMode, JankType::BufferStuffing, -4, 0, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -649,7 +650,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 82, refreshRate); @@ -666,9 +667,10 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { Fps refreshRate = Fps::fromPeriodNsecs(11); Fps renderRate = Fps::fromPeriodNsecs(30); EXPECT_CALL(*mTimeStats, - incrementJankyFrames( - TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne, - JankType::AppDeadlineMissed, -4, 0, 25})); + incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, + sLayerNameOne, sGameMode, + JankType::AppDeadlineMissed, -4, 0, + 25})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90}); @@ -676,7 +678,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -696,6 +698,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPres EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne, + sGameMode, JankType::Unknown | JankType::AppDeadlineMissed, 0, 0, 25})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -705,7 +708,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPres auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); // Trigger a prediction expiry flushTokens(); @@ -742,7 +745,7 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); // Set up the display frame mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11)); @@ -769,7 +772,7 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); // Set up the display frame mFrameTimeline->setSfWakeUp(token2, 20, Fps::fromPeriodNsecs(11)); @@ -815,7 +818,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); // Set up the display frame mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11)); @@ -1128,11 +1131,11 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setActualQueueTime(10); surfaceFrame1->setDropTime(15); @@ -1288,7 +1291,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpecte auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setActualQueueTime(appEndTime); surfaceFrame1->setAcquireFenceTime(appEndTime); @@ -1364,7 +1367,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDroppedFramesTraced auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); constexpr nsecs_t sfStartTime = std::chrono::nanoseconds(22ms).count(); constexpr nsecs_t sfEndTime = std::chrono::nanoseconds(30ms).count(); @@ -1433,7 +1436,7 @@ TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) { auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -1649,7 +1652,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1669,7 +1672,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1701,8 +1704,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne, - sLayerNameOne, JankType::PredictionError, -3, 5, - 0})); + sLayerNameOne, sGameMode, + JankType::PredictionError, -3, 5, 0})); addEmptyDisplayFrame(); @@ -1729,7 +1732,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1749,7 +1752,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1781,8 +1784,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne, - sLayerNameOne, JankType::PredictionError, -3, 5, - 0})); + sLayerNameOne, sGameMode, + JankType::PredictionError, -3, 5, 0})); addEmptyDisplayFrame(); @@ -1808,7 +1811,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 42, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1852,7 +1855,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(26); mFrameTimeline->setSfWakeUp(sfToken1, 32, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1872,7 +1875,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken2, 43, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1927,7 +1930,7 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1947,7 +1950,7 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(84); mFrameTimeline->setSfWakeUp(sfToken2, 112, Fps::fromPeriodNsecs(30)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54); @@ -2005,7 +2008,7 @@ TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffin auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -2025,7 +2028,7 @@ TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffin auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true); + sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(80); mFrameTimeline->setSfWakeUp(sfToken2, 82, Fps::fromPeriodNsecs(30)); // Setting previous latch time to 54, adjusted deadline will be 54 + vsyncTime(30) = 84 @@ -2081,7 +2084,7 @@ TEST_F(FrameTimelineTest, computeFps_singleDisplayFrame_returnsZero) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -2097,7 +2100,7 @@ TEST_F(FrameTimelineTest, computeFps_twoDisplayFrames_oneLayer) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -2107,7 +2110,7 @@ TEST_F(FrameTimelineTest, computeFps_twoDisplayFrames_oneLayer) { auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); @@ -2123,7 +2126,7 @@ TEST_F(FrameTimelineTest, computeFps_twoDisplayFrames_twoLayers) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -2133,7 +2136,7 @@ TEST_F(FrameTimelineTest, computeFps_twoDisplayFrames_twoLayers) { auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdTwo, sLayerNameTwo, sLayerNameTwo, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); @@ -2149,7 +2152,7 @@ TEST_F(FrameTimelineTest, computeFps_filtersOutLayers) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -2159,7 +2162,7 @@ TEST_F(FrameTimelineTest, computeFps_filtersOutLayers) { auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdTwo, sLayerNameTwo, sLayerNameTwo, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); @@ -2178,7 +2181,7 @@ TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) { auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -2188,7 +2191,7 @@ TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) { auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); @@ -2198,7 +2201,7 @@ TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) { auto surfaceFrame3 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdTwo, sLayerNameTwo, sLayerNameTwo, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence3 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame3->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame3); @@ -2208,7 +2211,7 @@ TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) { auto surfaceFrame4 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence4 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); surfaceFrame4->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame4); @@ -2218,7 +2221,7 @@ TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) { auto surfaceFrame5 = mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, - /*isBuffer*/ true); + /*isBuffer*/ true, sGameMode); auto presentFence5 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); // Dropped frames will be excluded from fps computation surfaceFrame5->setPresentState(SurfaceFrame::PresentState::Dropped); diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index 3e4e130a14..317cdf1592 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -54,6 +54,9 @@ using testing::StrEq; using testing::UnorderedElementsAre; using PowerMode = hardware::graphics::composer::V2_4::IComposerClient::PowerMode; +using SurfaceflingerStatsLayerInfo = android::surfaceflinger::SurfaceflingerStatsLayerInfo; +using SurfaceflingerStatsLayerInfoWrapper = + android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper; // clang-format off #define FMT_PROTO true @@ -71,6 +74,7 @@ using PowerMode = hardware::graphics::composer::V2_4::IComposerClient::PowerMode const constexpr Fps kRefreshRate0 = Fps(static_cast(REFRESH_RATE_0)); const constexpr Fps kRenderRate0 = Fps(static_cast(RENDER_RATE_0)); +static constexpr int32_t kGameMode = TimeStatsHelper::GameModeUnsupported; enum InputCommand : int32_t { ENABLE = 0, @@ -143,15 +147,16 @@ public: std::string inputCommand(InputCommand cmd, bool useProto); void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts, - TimeStats::SetFrameRateVote frameRateVote); + TimeStats::SetFrameRateVote frameRateVote, int32_t gameMode); int32_t genRandomInt32(int32_t begin, int32_t end); template void insertTimeRecord(const TimeStamp (&sequence)[N], int32_t id, uint64_t frameNumber, - nsecs_t ts, TimeStats::SetFrameRateVote frameRateVote = {}) { + nsecs_t ts, TimeStats::SetFrameRateVote frameRateVote = {}, + int32_t gameMode = kGameMode) { for (size_t i = 0; i < N; i++, ts += 1000000) { - setTimeStamp(sequence[i], id, frameNumber, ts, frameRateVote); + setTimeStamp(sequence[i], id, frameNumber, ts, frameRateVote, gameMode); } } @@ -200,11 +205,11 @@ static std::string genLayerName(int32_t layerId) { } void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts, - TimeStats::SetFrameRateVote frameRateVote) { + TimeStats::SetFrameRateVote frameRateVote, int32_t gameMode) { switch (type) { case TimeStamp::POST: - ASSERT_NO_FATAL_FAILURE( - mTimeStats->setPostTime(id, frameNumber, genLayerName(id), UID_0, ts)); + ASSERT_NO_FATAL_FAILURE(mTimeStats->setPostTime(id, frameNumber, genLayerName(id), + UID_0, ts, gameMode)); break; case TimeStamp::ACQUIRE: ASSERT_NO_FATAL_FAILURE(mTimeStats->setAcquireTime(id, frameNumber, ts)); @@ -221,12 +226,14 @@ void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumbe break; case TimeStamp::PRESENT: ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentTime(id, frameNumber, ts, kRefreshRate0, - kRenderRate0, frameRateVote)); + kRenderRate0, frameRateVote, + gameMode)); break; case TimeStamp::PRESENT_FENCE: - ASSERT_NO_FATAL_FAILURE( - mTimeStats->setPresentFence(id, frameNumber, std::make_shared(ts), - kRefreshRate0, kRenderRate0, frameRateVote)); + ASSERT_NO_FATAL_FAILURE(mTimeStats->setPresentFence(id, frameNumber, + std::make_shared(ts), + kRefreshRate0, kRenderRate0, + frameRateVote, gameMode)); break; default: ALOGD("Invalid timestamp type"); @@ -319,22 +326,24 @@ TEST_F(TimeStatsTest, canIncreaseJankyFramesForLayer) { insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3}); - mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3}); + kGameMode, JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, + 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::DisplayHAL, 1, 2, 3}); + kGameMode, JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, + 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::AppDeadlineMissed, 1, 2, 3}); + kGameMode, JankType::DisplayHAL, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerScheduling, 1, 2, 3}); + kGameMode, JankType::AppDeadlineMissed, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::PredictionError, 1, 2, 3}); + kGameMode, JankType::SurfaceFlingerScheduling, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2, - 3}); + kGameMode, JankType::PredictionError, 1, 2, 3}); + mTimeStats->incrementJankyFrames( + {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), kGameMode, + JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::None, 1, 2, 3}); + kGameMode, JankType::None, 1, 2, 3}); const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING)); std::string expectedResult = @@ -872,22 +881,24 @@ TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) { std::make_shared(std::chrono::nanoseconds(1ms).count())); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3}); - mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3}); + kGameMode, JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, + 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::DisplayHAL, 1, 2, 3}); + kGameMode, JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, + 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::AppDeadlineMissed, 1, 2, 3}); + kGameMode, JankType::DisplayHAL, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerScheduling, 1, 2, 3}); + kGameMode, JankType::AppDeadlineMissed, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::PredictionError, 1, 2, 3}); + kGameMode, JankType::SurfaceFlingerScheduling, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2, - 3}); + kGameMode, JankType::PredictionError, 1, 2, 3}); + mTimeStats->incrementJankyFrames( + {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), kGameMode, + JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2, 3}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::None, 1, 2, 3}); + kGameMode, JankType::None, 1, 2, 3}); EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty()); @@ -1039,34 +1050,36 @@ TEST_F(TimeStatsTest, globalStatsCallback) { mTimeStats->setPresentFenceGlobal(std::make_shared(5000000)); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerCpuDeadlineMissed, + kGameMode, JankType::SurfaceFlingerCpuDeadlineMissed, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerGpuDeadlineMissed, + kGameMode, JankType::SurfaceFlingerGpuDeadlineMissed, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::DisplayHAL, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); - mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::AppDeadlineMissed, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); - mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerScheduling, DISPLAY_DEADLINE_DELTA, + kGameMode, JankType::DisplayHAL, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::PredictionError, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); + kGameMode, JankType::AppDeadlineMissed, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, + APP_DEADLINE_DELTA}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::AppDeadlineMissed | JankType::BufferStuffing, + kGameMode, JankType::SurfaceFlingerScheduling, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::BufferStuffing, DISPLAY_DEADLINE_DELTA, + kGameMode, JankType::PredictionError, DISPLAY_DEADLINE_DELTA, + DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); + mTimeStats->incrementJankyFrames( + {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), kGameMode, + JankType::AppDeadlineMissed | JankType::BufferStuffing, DISPLAY_DEADLINE_DELTA, + DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); + mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + kGameMode, JankType::BufferStuffing, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::None, DISPLAY_DEADLINE_DELTA, + kGameMode, JankType::None, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA}); std::string pulledData; @@ -1157,7 +1170,8 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { constexpr nsecs_t APP_DEADLINE_DELTA_3MS = 3'000'000; EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000, {}, + TimeStatsHelper::GameModeStandard); for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) { mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire); } @@ -1170,43 +1184,50 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { TimeStats::SetFrameRateVote::FrameRateCompatibility::ExactOrMultiple, .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::NotRequired, }; - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate60); - - mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerCpuDeadlineMissed, - DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, - APP_DEADLINE_DELTA_3MS}); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate60, + TimeStatsHelper::GameModeStandard); + + mTimeStats->incrementJankyFrames( + {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + TimeStatsHelper::GameModeStandard, JankType::SurfaceFlingerCpuDeadlineMissed, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); + mTimeStats->incrementJankyFrames( + {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + TimeStatsHelper::GameModeStandard, JankType::SurfaceFlingerGpuDeadlineMissed, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::SurfaceFlingerGpuDeadlineMissed, + TimeStatsHelper::GameModeStandard, JankType::DisplayHAL, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::DisplayHAL, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); - mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + TimeStatsHelper::GameModeStandard, JankType::AppDeadlineMissed, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + TimeStatsHelper::GameModeStandard, JankType::SurfaceFlingerScheduling, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_2MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::PredictionError, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_2MS}); + TimeStatsHelper::GameModeStandard, JankType::PredictionError, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, + APP_DEADLINE_DELTA_2MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), + TimeStatsHelper::GameModeStandard, JankType::AppDeadlineMissed | JankType::BufferStuffing, DISPLAY_DEADLINE_DELTA, APP_DEADLINE_DELTA_2MS, APP_DEADLINE_DELTA_2MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - JankType::None, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); + TimeStatsHelper::GameModeStandard, JankType::None, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, + APP_DEADLINE_DELTA_3MS}); std::string pulledData; EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); - android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + SurfaceflingerStatsLayerInfoWrapper atomList; ASSERT_TRUE(atomList.ParseFromString(pulledData)); ASSERT_EQ(atomList.atom_size(), 1); - const android::surfaceflinger::SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); + const SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); EXPECT_EQ(atom.layer_name(), genLayerName(LAYER_ID_0)); EXPECT_EQ(atom.total_frames(), 1); @@ -1236,6 +1257,7 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { (int)frameRate60.frameRateCompatibility); EXPECT_EQ((int)atom.set_frame_rate_vote().seamlessness(), (int)frameRate60.seamlessness); EXPECT_THAT(atom.app_deadline_misses(), HistogramEq(buildExpectedHistogram({3, 2}, {4, 3}))); + EXPECT_EQ(atom.game_mode(), SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD); SFTimeStatsGlobalProto globalProto; ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO))); @@ -1268,6 +1290,92 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { EXPECT_THAT(result, Not(HasSubstr(expectedMissing))); } +TEST_F(TimeStatsTest, layerStatsCallback_multipleGameModes) { + constexpr size_t LATE_ACQUIRE_FRAMES = 2; + constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3; + EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); + + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000, {}, + TimeStatsHelper::GameModeStandard); + for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) { + mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire); + } + for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) { + mTimeStats->incrementBadDesiredPresent(LAYER_ID_0); + } + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, {}, + TimeStatsHelper::GameModeStandard); + + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000, {}, + TimeStatsHelper::GameModePerformance); + + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 4000000, {}, TimeStatsHelper::GameModeBattery); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 5, 4000000, {}, TimeStatsHelper::GameModeBattery); + + std::string pulledData; + EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); + + SurfaceflingerStatsLayerInfoWrapper atomList; + ASSERT_TRUE(atomList.ParseFromString(pulledData)); + // The first time record is never uploaded to stats. + ASSERT_EQ(atomList.atom_size(), 3); + // Layers are ordered based on the hash in LayerStatsKey. For this test, the order happens to + // be: 0 - Battery 1 - Performance 2 - Standard + const SurfaceflingerStatsLayerInfo& atom0 = atomList.atom(0); + + EXPECT_EQ(atom0.layer_name(), genLayerName(LAYER_ID_0)); + EXPECT_EQ(atom0.total_frames(), 2); + EXPECT_EQ(atom0.dropped_frames(), 0); + EXPECT_THAT(atom0.present_to_present(), HistogramEq(buildExpectedHistogram({0, 1}, {1, 1}))); + EXPECT_THAT(atom0.post_to_present(), HistogramEq(buildExpectedHistogram({4}, {2}))); + EXPECT_THAT(atom0.acquire_to_present(), HistogramEq(buildExpectedHistogram({3}, {2}))); + EXPECT_THAT(atom0.latch_to_present(), HistogramEq(buildExpectedHistogram({2}, {2}))); + EXPECT_THAT(atom0.desired_to_present(), HistogramEq(buildExpectedHistogram({1}, {2}))); + EXPECT_THAT(atom0.post_to_acquire(), HistogramEq(buildExpectedHistogram({1}, {2}))); + EXPECT_EQ(atom0.late_acquire_frames(), 0); + EXPECT_EQ(atom0.bad_desired_present_frames(), 0); + EXPECT_EQ(atom0.uid(), UID_0); + EXPECT_EQ(atom0.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0); + EXPECT_EQ(atom0.render_rate_bucket(), RENDER_RATE_BUCKET_0); + EXPECT_EQ(atom0.game_mode(), SurfaceflingerStatsLayerInfo::GAME_MODE_BATTERY); + + const SurfaceflingerStatsLayerInfo& atom1 = atomList.atom(1); + + EXPECT_EQ(atom1.layer_name(), genLayerName(LAYER_ID_0)); + EXPECT_EQ(atom1.total_frames(), 1); + EXPECT_EQ(atom1.dropped_frames(), 0); + EXPECT_THAT(atom1.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_THAT(atom1.post_to_present(), HistogramEq(buildExpectedHistogram({4}, {1}))); + EXPECT_THAT(atom1.acquire_to_present(), HistogramEq(buildExpectedHistogram({3}, {1}))); + EXPECT_THAT(atom1.latch_to_present(), HistogramEq(buildExpectedHistogram({2}, {1}))); + EXPECT_THAT(atom1.desired_to_present(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_THAT(atom1.post_to_acquire(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_EQ(atom1.late_acquire_frames(), 0); + EXPECT_EQ(atom1.bad_desired_present_frames(), 0); + EXPECT_EQ(atom1.uid(), UID_0); + EXPECT_EQ(atom1.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0); + EXPECT_EQ(atom1.render_rate_bucket(), RENDER_RATE_BUCKET_0); + EXPECT_EQ(atom1.game_mode(), SurfaceflingerStatsLayerInfo::GAME_MODE_PERFORMANCE); + + const SurfaceflingerStatsLayerInfo& atom2 = atomList.atom(2); + + EXPECT_EQ(atom2.layer_name(), genLayerName(LAYER_ID_0)); + EXPECT_EQ(atom2.total_frames(), 1); + EXPECT_EQ(atom2.dropped_frames(), 0); + EXPECT_THAT(atom2.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_THAT(atom2.post_to_present(), HistogramEq(buildExpectedHistogram({4}, {1}))); + EXPECT_THAT(atom2.acquire_to_present(), HistogramEq(buildExpectedHistogram({3}, {1}))); + EXPECT_THAT(atom2.latch_to_present(), HistogramEq(buildExpectedHistogram({2}, {1}))); + EXPECT_THAT(atom2.desired_to_present(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_THAT(atom2.post_to_acquire(), HistogramEq(buildExpectedHistogram({1}, {1}))); + EXPECT_EQ(atom2.late_acquire_frames(), LATE_ACQUIRE_FRAMES); + EXPECT_EQ(atom2.bad_desired_present_frames(), BAD_DESIRED_PRESENT_FRAMES); + EXPECT_EQ(atom2.uid(), UID_0); + EXPECT_EQ(atom2.display_refresh_rate_bucket(), REFRESH_RATE_BUCKET_0); + EXPECT_EQ(atom2.render_rate_bucket(), RENDER_RATE_BUCKET_0); + EXPECT_EQ(atom2.game_mode(), SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD); +} + TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) { EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); @@ -1279,7 +1387,7 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) { std::string pulledData; EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); - android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + SurfaceflingerStatsLayerInfoWrapper atomList; ASSERT_TRUE(atomList.ParseFromString(pulledData)); ASSERT_EQ(atomList.atom_size(), 2); std::vector actualLayerNames = {atomList.atom(0).layer_name(), @@ -1304,10 +1412,10 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) { std::string pulledData; EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); - android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + SurfaceflingerStatsLayerInfoWrapper atomList; ASSERT_TRUE(atomList.ParseFromString(pulledData)); ASSERT_EQ(atomList.atom_size(), 1); - const android::surfaceflinger::SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); + const SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); EXPECT_THAT(atom.present_to_present(), HistogramEq(buildExpectedHistogram({1, 2}, {2, 1}))); } @@ -1323,10 +1431,10 @@ TEST_F(TimeStatsTest, layerStatsCallback_limitsHistogramBuckets) { std::string pulledData; EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); - android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + SurfaceflingerStatsLayerInfoWrapper atomList; ASSERT_TRUE(atomList.ParseFromString(pulledData)); ASSERT_EQ(atomList.atom_size(), 1); - const android::surfaceflinger::SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); + const SurfaceflingerStatsLayerInfo& atom = atomList.atom(0); EXPECT_THAT(atom.present_to_present(), HistogramEq(buildExpectedHistogram({1}, {2}))); } @@ -1343,7 +1451,7 @@ TEST_F(TimeStatsTest, layerStatsCallback_limitsLayers) { std::string pulledData; EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); - android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList; + SurfaceflingerStatsLayerInfoWrapper atomList; ASSERT_TRUE(atomList.ParseFromString(pulledData)); ASSERT_EQ(atomList.atom_size(), 1); EXPECT_EQ(atomList.atom(0).layer_name(), genLayerName(LAYER_ID_1)); @@ -1372,7 +1480,7 @@ TEST_F(TimeStatsTest, canSurviveMonkey) { TimeStamp type = static_cast(genRandomInt32(TIME_STAMP_BEGIN, TIME_STAMP_END)); const int32_t ts = genRandomInt32(1, 1000000000); ALOGV("type[%d], layerId[%d], frameNumber[%d], ts[%d]", type, layerId, frameNumber, ts); - setTimeStamp(type, layerId, frameNumber, ts, {}); + setTimeStamp(type, layerId, frameNumber, ts, {}, kGameMode); } } @@ -1383,8 +1491,8 @@ TEST_F(TimeStatsTest, refreshRateIsClampedToNearestBucket) { EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); - mTimeStats->incrementJankyFrames( - {fps, std::nullopt, UID_0, genLayerName(LAYER_ID_0), JankType::None, 0, 0, 0}); + mTimeStats->incrementJankyFrames({fps, std::nullopt, UID_0, genLayerName(LAYER_ID_0), + kGameMode, JankType::None, 0, 0, 0}); const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING)); std::string expectedResult = "displayRefreshRate = " + std::to_string(bucket) + " fps"; EXPECT_THAT(result, HasSubstr(expectedResult)) << "failed for " << fps; diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h index 526a847614..5aebd2f20e 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h @@ -41,18 +41,19 @@ public: MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t)); MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t)); MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr&)); - MOCK_METHOD5(setPostTime, void(int32_t, uint64_t, const std::string&, uid_t, nsecs_t)); + MOCK_METHOD6(setPostTime, void(int32_t, uint64_t, const std::string&, uid_t, nsecs_t, int32_t)); MOCK_METHOD2(incrementLatchSkipped, void(int32_t layerId, LatchSkipReason reason)); MOCK_METHOD1(incrementBadDesiredPresent, void(int32_t layerId)); MOCK_METHOD3(setLatchTime, void(int32_t, uint64_t, nsecs_t)); MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t)); MOCK_METHOD3(setAcquireTime, void(int32_t, uint64_t, nsecs_t)); MOCK_METHOD3(setAcquireFence, void(int32_t, uint64_t, const std::shared_ptr&)); - MOCK_METHOD6(setPresentTime, - void(int32_t, uint64_t, nsecs_t, Fps, std::optional, SetFrameRateVote)); - MOCK_METHOD6(setPresentFence, + MOCK_METHOD7(setPresentTime, + void(int32_t, uint64_t, nsecs_t, Fps, std::optional, SetFrameRateVote, + int32_t)); + MOCK_METHOD7(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr&, Fps, std::optional, - SetFrameRateVote)); + SetFrameRateVote, int32_t)); MOCK_METHOD1(incrementJankyFrames, void(const JankyFramesInfo&)); MOCK_METHOD1(onDestroy, void(int32_t)); MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t)); -- cgit v1.2.3-59-g8ed1b