From f9096655b6c0dc377786553486a11c0197ab91ea Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 20 Jul 2021 18:49:42 -0700 Subject: SurfaceFlinger: Safely cast from IBinder to Layer::Handle Bug: b/193034677, b/193034683, b/193033243 Test: go/wm-smoke, presubmit Change-Id: Iece64fca254edfd0b82e05ad9629824b2364cc13 --- services/surfaceflinger/Layer.cpp | 42 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index c5dcd8ee8f..473c68c924 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -819,11 +819,7 @@ void Layer::setZOrderRelativeOf(const wp& relativeOf) { } bool Layer::setRelativeLayer(const sp& relativeToHandle, int32_t relativeZ) { - sp handle = static_cast(relativeToHandle.get()); - if (handle == nullptr) { - return false; - } - sp relative = handle->owner.promote(); + sp relative = fromHandle(relativeToHandle).promote(); if (relative == nullptr) { return false; } @@ -1598,8 +1594,7 @@ void Layer::setChildrenDrawingParent(const sp& newParent) { bool Layer::reparent(const sp& newParentHandle) { sp newParent; if (newParentHandle != nullptr) { - auto handle = static_cast(newParentHandle.get()); - newParent = handle->owner.promote(); + newParent = fromHandle(newParentHandle).promote(); if (newParent == nullptr) { ALOGE("Unable to promote Layer handle"); return false; @@ -1974,24 +1969,10 @@ void Layer::commitChildList() { mDrawingParent = mCurrentParent; } -static wp extractLayerFromBinder(const wp& weakBinderHandle) { - if (weakBinderHandle == nullptr) { - return nullptr; - } - sp binderHandle = weakBinderHandle.promote(); - if (binderHandle == nullptr) { - return nullptr; - } - sp handle = static_cast(binderHandle.get()); - if (handle == nullptr) { - return nullptr; - } - return handle->owner; -} void Layer::setInputInfo(const WindowInfo& info) { mDrawingState.inputInfo = info; - mDrawingState.touchableRegionCrop = extractLayerFromBinder(info.touchableRegionCropHandle); + mDrawingState.touchableRegionCrop = fromHandle(info.touchableRegionCropHandle.promote()); mDrawingState.modified = true; mFlinger->mInputInfoChanged = true; setTransactionFlags(eTransactionNeeded); @@ -2548,6 +2529,23 @@ void Layer::setClonedChild(const sp& clonedChild) { mFlinger->mNumClones++; } +const String16 Layer::Handle::kDescriptor = String16("android.Layer.Handle"); + +wp Layer::fromHandle(const sp& handleBinder) { + if (handleBinder == nullptr) { + return nullptr; + } + + BBinder* b = handleBinder->localBinder(); + if (b == nullptr || b->getInterfaceDescriptor() != Handle::kDescriptor) { + return nullptr; + } + + // We can safely cast this binder since its local and we verified its interface descriptor. + sp handle = static_cast(handleBinder.get()); + return handle->owner; +} + // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { -- cgit v1.2.3-59-g8ed1b From 29fa146d8d745cee950a1ed82ddb500fc6d6c771 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 27 Apr 2021 15:51:50 -0700 Subject: SF: Consolidate layer-to-output filtering Add ui::LayerFilter for less repetitive CE plumbing. Make ui::LayerStack a type, and (unlike the alias) use it everywhere. Remove redundant state in CE's DisplayCreationArgs. Bug: 182939859 Test: Display cutout is excluded in screenshots. Test: libcompositionengine_test Test: libsurfaceflinger_unittest Test: SurfaceFlinger_test Test: libgui_test Change-Id: Ib854d354af7aef7168001c34297e875b71d53622 --- cmds/surfacereplayer/replayer/Replayer.cpp | 4 +- libs/gui/LayerState.cpp | 18 +-- libs/gui/SurfaceComposerClient.cpp | 4 +- libs/gui/include/gui/LayerState.h | 17 ++- libs/gui/include/gui/SurfaceComposerClient.h | 4 +- libs/gui/tests/BLASTBufferQueue_test.cpp | 12 +- libs/ui/include/ui/DisplayState.h | 7 +- libs/ui/include/ui/LayerStack.h | 78 +++++++++++ .../compositionengine/DisplayCreationArgs.h | 16 --- .../compositionengine/LayerFECompositionState.h | 7 +- .../include/compositionengine/Output.h | 21 +-- .../include/compositionengine/impl/Display.h | 3 +- .../include/compositionengine/impl/DumpHelpers.h | 14 +- .../include/compositionengine/impl/Output.h | 8 +- .../impl/OutputCompositionState.h | 8 +- .../include/compositionengine/mock/Output.h | 7 +- .../CompositionEngine/src/Display.cpp | 11 +- .../CompositionEngine/src/DumpHelpers.cpp | 16 ++- .../CompositionEngine/src/Output.cpp | 25 ++-- .../src/OutputCompositionState.cpp | 4 +- .../CompositionEngine/tests/DisplayTest.cpp | 59 +++----- .../CompositionEngine/tests/OutputTest.cpp | 149 ++++++++++----------- services/surfaceflinger/DisplayDevice.cpp | 4 +- services/surfaceflinger/DisplayDevice.h | 6 +- services/surfaceflinger/Layer.cpp | 71 +++++----- services/surfaceflinger/Layer.h | 33 +++-- services/surfaceflinger/LayerVector.cpp | 4 +- services/surfaceflinger/RefreshRateOverlay.cpp | 2 +- services/surfaceflinger/RefreshRateOverlay.h | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 98 ++++++-------- services/surfaceflinger/SurfaceInterceptor.cpp | 12 +- services/surfaceflinger/SurfaceInterceptor.h | 5 +- services/surfaceflinger/tests/Credentials_test.cpp | 2 +- services/surfaceflinger/tests/EffectLayer_test.cpp | 2 +- services/surfaceflinger/tests/IPC_test.cpp | 6 +- .../surfaceflinger/tests/LayerTransactionTest.h | 4 +- .../LayerTypeAndRenderTypeTransaction_test.cpp | 3 +- services/surfaceflinger/tests/LayerUpdate_test.cpp | 2 +- services/surfaceflinger/tests/MirrorLayer_test.cpp | 2 +- .../tests/MultiDisplayLayerBounds_test.cpp | 13 +- services/surfaceflinger/tests/RelativeZ_test.cpp | 2 +- .../surfaceflinger/tests/ScreenCapture_test.cpp | 8 +- .../tests/SurfaceInterceptor_test.cpp | 4 +- .../tests/TransactionTestHarnesses.h | 2 +- .../tests/WindowInfosListener_test.cpp | 4 +- .../tests/fakehwc/SFFakeHwc_test.cpp | 22 +-- .../tests/unittests/CompositionTest.cpp | 8 +- .../tests/unittests/DisplayTransactionTest.cpp | 8 +- .../unittests/DisplayTransactionTestHelpers.h | 8 +- .../SurfaceFlinger_HandleTransactionLockedTest.cpp | 4 +- .../SurfaceFlinger_OnInitializeDisplaysTest.cpp | 12 +- .../SurfaceFlinger_SetDisplayStateTest.cpp | 16 ++- 52 files changed, 414 insertions(+), 448 deletions(-) create mode 100644 libs/ui/include/ui/LayerStack.h (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index cfd42fec30..3f7c7d6a7b 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -528,7 +528,7 @@ void Replayer::setTransparentRegionHint(SurfaceComposerClient::Transaction& t, void Replayer::setLayerStack(SurfaceComposerClient::Transaction& t, layer_id id, const LayerStackChange& lsc) { ALOGV("Layer %d: Setting LayerStack -- layer_stack=%d", id, lsc.layer_stack()); - t.setLayerStack(mLayers[id], lsc.layer_stack()); + t.setLayerStack(mLayers[id], ui::LayerStack::fromValue(lsc.layer_stack())); } void Replayer::setHiddenFlag(SurfaceComposerClient::Transaction& t, @@ -566,7 +566,7 @@ void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t, void Replayer::setDisplayLayerStack(SurfaceComposerClient::Transaction& t, display_id id, const LayerStackChange& lsc) { - t.setDisplayLayerStack(mDisplays[id], lsc.layer_stack()); + t.setDisplayLayerStack(mDisplays[id], ui::LayerStack::fromValue(lsc.layer_stack())); } void Replayer::setDisplaySize(SurfaceComposerClient::Transaction& t, diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 23895c0c9f..95a2f602b9 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -41,7 +41,6 @@ layer_state_t::layer_state_t() z(0), w(0), h(0), - layerStack(0), alpha(0), flags(0), mask(0), @@ -86,7 +85,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeInt32, z); SAFE_PARCEL(output.writeUint32, w); SAFE_PARCEL(output.writeUint32, h); - SAFE_PARCEL(output.writeUint32, layerStack); + SAFE_PARCEL(output.writeUint32, layerStack.id); SAFE_PARCEL(output.writeFloat, alpha); SAFE_PARCEL(output.writeUint32, flags); SAFE_PARCEL(output.writeUint32, mask); @@ -187,7 +186,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readInt32, &z); SAFE_PARCEL(input.readUint32, &w); SAFE_PARCEL(input.readUint32, &h); - SAFE_PARCEL(input.readUint32, &layerStack); + SAFE_PARCEL(input.readUint32, &layerStack.id); SAFE_PARCEL(input.readFloat, &alpha); SAFE_PARCEL(input.readUint32, &flags); @@ -314,21 +313,14 @@ status_t ComposerState::read(const Parcel& input) { return state.read(input); } -DisplayState::DisplayState() - : what(0), - layerStack(0), - flags(0), - layerStackSpaceRect(Rect::EMPTY_RECT), - orientedDisplaySpaceRect(Rect::EMPTY_RECT), - width(0), - height(0) {} +DisplayState::DisplayState() = default; status_t DisplayState::write(Parcel& output) const { SAFE_PARCEL(output.writeStrongBinder, token); SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(surface)); SAFE_PARCEL(output.writeUint32, what); - SAFE_PARCEL(output.writeUint32, layerStack); SAFE_PARCEL(output.writeUint32, flags); + SAFE_PARCEL(output.writeUint32, layerStack.id); SAFE_PARCEL(output.writeUint32, toRotationInt(orientation)); SAFE_PARCEL(output.write, layerStackSpaceRect); SAFE_PARCEL(output.write, orientedDisplaySpaceRect); @@ -344,8 +336,8 @@ status_t DisplayState::read(const Parcel& input) { surface = interface_cast(tmpBinder); SAFE_PARCEL(input.readUint32, &what); - SAFE_PARCEL(input.readUint32, &layerStack); SAFE_PARCEL(input.readUint32, &flags); + SAFE_PARCEL(input.readUint32, &layerStack.id); uint32_t tmpUint = 0; SAFE_PARCEL(input.readUint32, &tmpUint); orientation = ui::toRotation(tmpUint); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index f620f5ae07..c3d632fa01 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1087,7 +1087,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayerStack( - const sp& sc, uint32_t layerStack) { + const sp& sc, ui::LayerStack layerStack) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; @@ -1751,7 +1751,7 @@ status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp } void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp& token, - uint32_t layerStack) { + ui::LayerStack layerStack) { DisplayState& s(getDisplayState(token)); s.layerStack = layerStack; s.what |= DisplayState::eLayerStackChanged; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index b27d9cf2bc..427f2a5ce0 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -143,7 +144,7 @@ struct layer_state_t { int32_t z; uint32_t w; uint32_t h; - uint32_t layerStack; + ui::LayerStack layerStack = ui::DEFAULT_LAYER_STACK; float alpha; uint32_t flags; uint32_t mask; @@ -262,11 +263,12 @@ struct DisplayState { DisplayState(); void merge(const DisplayState& other); - uint32_t what; + uint32_t what = 0; + uint32_t flags = 0; sp token; sp surface; - uint32_t layerStack; - uint32_t flags; + + ui::LayerStack layerStack = ui::DEFAULT_LAYER_STACK; // These states define how layers are projected onto the physical display. // @@ -280,10 +282,11 @@ struct DisplayState { // will be additionally rotated by 90 degrees around the origin clockwise and translated by (W, // 0). ui::Rotation orientation = ui::ROTATION_0; - Rect layerStackSpaceRect; - Rect orientedDisplaySpaceRect; + Rect layerStackSpaceRect = Rect::EMPTY_RECT; + Rect orientedDisplaySpaceRect = Rect::EMPTY_RECT; - uint32_t width, height; + uint32_t width = 0; + uint32_t height = 0; status_t write(Parcel& output) const; status_t read(const Parcel& input); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 869cef6cdc..ec68ca9798 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -456,7 +456,7 @@ public: int backgroundBlurRadius); Transaction& setBlurRegions(const sp& sc, const std::vector& regions); - Transaction& setLayerStack(const sp& sc, uint32_t layerStack); + Transaction& setLayerStack(const sp&, ui::LayerStack); Transaction& setMetadata(const sp& sc, uint32_t key, const Parcel& p); /// Reparents the current layer to the new parent handle. The new parent must not be null. @@ -566,7 +566,7 @@ public: status_t setDisplaySurface(const sp& token, const sp& bufferProducer); - void setDisplayLayerStack(const sp& token, uint32_t layerStack); + void setDisplayLayerStack(const sp& token, ui::LayerStack); void setDisplayFlags(const sp& token, uint32_t flags); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 9082d275a2..26d902d849 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -128,7 +128,7 @@ protected: mDisplayToken = mClient->getInternalDisplayToken(); ASSERT_NE(nullptr, mDisplayToken.get()); Transaction t; - t.setDisplayLayerStack(mDisplayToken, 0); + t.setDisplayLayerStack(mDisplayToken, ui::DEFAULT_LAYER_STACK); t.apply(); t.clear(); @@ -142,7 +142,7 @@ protected: mDisplayHeight, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState, /*parent*/ nullptr); - t.setLayerStack(mSurfaceControl, 0) + t.setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK) .setLayer(mSurfaceControl, std::numeric_limits::max()) .show(mSurfaceControl) .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) @@ -490,7 +490,7 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { ISurfaceComposerClient::eFXSurfaceEffect); ASSERT_NE(nullptr, bg.get()); Transaction t; - t.setLayerStack(bg, 0) + t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK) .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) .setColor(bg, half3{0, 0, 0}) .setLayer(bg, 0) @@ -545,7 +545,7 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) { ISurfaceComposerClient::eFXSurfaceEffect); ASSERT_NE(nullptr, bg.get()); Transaction t; - t.setLayerStack(bg, 0) + t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK) .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) .setColor(bg, half3{0, 0, 0}) .setLayer(bg, 0) @@ -612,7 +612,7 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) { ISurfaceComposerClient::eFXSurfaceEffect); ASSERT_NE(nullptr, bg.get()); Transaction t; - t.setLayerStack(bg, 0) + t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK) .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) .setColor(bg, half3{0, 0, 0}) .setLayer(bg, 0) @@ -733,7 +733,7 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { ISurfaceComposerClient::eFXSurfaceBufferState); ASSERT_NE(nullptr, bgSurface.get()); Transaction t; - t.setLayerStack(bgSurface, 0) + t.setLayerStack(bgSurface, ui::DEFAULT_LAYER_STACK) .show(bgSurface) .setDataspace(bgSurface, ui::Dataspace::V0_SRGB) .setLayer(bgSurface, std::numeric_limits::max() - 1) diff --git a/libs/ui/include/ui/DisplayState.h b/libs/ui/include/ui/DisplayState.h index 70a0d50611..98ee35652a 100644 --- a/libs/ui/include/ui/DisplayState.h +++ b/libs/ui/include/ui/DisplayState.h @@ -16,21 +16,18 @@ #pragma once +#include #include #include -#include #include namespace android::ui { -using LayerStack = uint32_t; -constexpr LayerStack NO_LAYER_STACK = static_cast(-1); - // Transactional state of physical or virtual display. Note that libgui defines // android::DisplayState as a superset of android::ui::DisplayState. struct DisplayState { - LayerStack layerStack = NO_LAYER_STACK; + LayerStack layerStack; Rotation orientation = ROTATION_0; Size layerStackSpaceRect; }; diff --git a/libs/ui/include/ui/LayerStack.h b/libs/ui/include/ui/LayerStack.h new file mode 100644 index 0000000000..d6ffeb7fad --- /dev/null +++ b/libs/ui/include/ui/LayerStack.h @@ -0,0 +1,78 @@ +/* + * 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 +#include +#include + +namespace android::ui { + +// A LayerStack identifies a Z-ordered group of layers. A layer can only be associated to a single +// LayerStack, but a LayerStack can be associated to multiple displays, mirroring the same content. +struct LayerStack { + uint32_t id = UINT32_MAX; + + template + static constexpr LayerStack fromValue(T v) { + if (ftl::cast_safety(v) == ftl::CastSafety::kSafe) { + return {static_cast(v)}; + } + + ALOGW("Invalid layer stack %s", ftl::to_string(v).c_str()); + return {}; + } +}; + +constexpr LayerStack INVALID_LAYER_STACK; +constexpr LayerStack DEFAULT_LAYER_STACK{0u}; + +inline bool operator==(LayerStack lhs, LayerStack rhs) { + return lhs.id == rhs.id; +} + +inline bool operator!=(LayerStack lhs, LayerStack rhs) { + return !(lhs == rhs); +} + +inline bool operator>(LayerStack lhs, LayerStack rhs) { + return lhs.id > rhs.id; +} + +// A LayerFilter determines if a layer is included for output to a display. +struct LayerFilter { + LayerStack layerStack; + + // True if the layer is only output to internal displays, i.e. excluded from screenshots, screen + // recordings, and mirroring to virtual or external displays. Used for display cutout overlays. + bool toInternalDisplay = false; + + // Returns true if the input filter can be output to this filter. + bool includes(LayerFilter other) const { + // The layer stacks must match. + if (other.layerStack == INVALID_LAYER_STACK || other.layerStack != layerStack) { + return false; + } + + // The output must be to an internal display if the input filter has that constraint. + return !other.toInternalDisplay || toInternalDisplay; + } +}; + +} // namespace android::ui diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h index 526e7daa80..98c4af487e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h @@ -36,18 +36,12 @@ class CompositionEngine; struct DisplayCreationArgs { DisplayId id; - // Unset for virtual displays - std::optional connectionType; - // Size of the display in pixels ui::Size pixels = ui::kInvalidSize; // True if this display should be considered secure bool isSecure = false; - // Gives the initial layer stack id to be used for the display - uint32_t layerStackId = ~0u; - // Optional pointer to the power advisor interface, if one is needed for // this display. Hwc2::PowerAdvisor* powerAdvisor = nullptr; @@ -69,11 +63,6 @@ public: return *this; } - DisplayCreationArgsBuilder& setConnectionType(ui::DisplayConnectionType connectionType) { - mArgs.connectionType = connectionType; - return *this; - } - DisplayCreationArgsBuilder& setPixels(ui::Size pixels) { mArgs.pixels = pixels; return *this; @@ -84,11 +73,6 @@ public: return *this; } - DisplayCreationArgsBuilder& setLayerStackId(uint32_t layerStackId) { - mArgs.layerStackId = layerStackId; - return *this; - } - DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) { mArgs.powerAdvisor = powerAdvisor; return *this; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index a45be8a7a2..ecb4e6d79d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -93,11 +94,9 @@ struct LayerFECompositionState { /* * Visibility state */ - // the layer stack this layer belongs to - std::optional layerStackId; - // If true, this layer should be only visible on the internal display - bool internalOnly{false}; + // The filter that determines which outputs include this layer + ui::LayerFilter outputFilter; // If false, this layer should not be considered visible bool isVisible{true}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 15a86af037..28baef8726 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -180,9 +181,8 @@ public: // output. virtual ui::Transform::RotationFlags getTransformHint() const = 0; - // Sets the layer stack filtering settings for this output. See - // belongsInOutput for full details. - virtual void setLayerStackFilter(uint32_t layerStackId, bool isInternal) = 0; + // Sets the filter for this output. See Output::includesLayer. + virtual void setLayerFilter(ui::LayerFilter) = 0; // Sets the output color mode virtual void setColorProfile(const ColorProfile&) = 0; @@ -224,17 +224,10 @@ public: // If repaintEverything is true, this will be the full display bounds. virtual Region getDirtyRegion(bool repaintEverything) const = 0; - // Tests whether a given layerStackId belongs in this output. - // A layer belongs to the output if its layerStackId matches the of the output layerStackId, - // unless the layer should display on the primary output only and this is not the primary output - - // A layer belongs to the output if its layerStackId matches. Additionally - // if the layer should only show in the internal (primary) display only and - // this output allows that. - virtual bool belongsInOutput(std::optional layerStackId, bool internalOnly) const = 0; - - // Determines if a layer belongs to the output. - virtual bool belongsInOutput(const sp&) const = 0; + // Returns whether the output includes a layer, based on their respective filters. + // See Output::setLayerFilter. + virtual bool includesLayer(ui::LayerFilter) const = 0; + virtual bool includesLayer(const sp&) const = 0; // Returns a pointer to the output layer corresponding to the given layer on // this output, or nullptr if the layer does not have one diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index bb540ea7ee..b407267560 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -83,9 +83,8 @@ public: std::unique_ptr createOutputLayer(const sp&) const; private: - bool mIsVirtual = false; - bool mIsDisconnected = false; DisplayId mId; + bool mIsDisconnected = false; Hwc2::PowerAdvisor* mPowerAdvisor = nullptr; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h index 6b9597b2d5..7521324756 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -52,13 +53,14 @@ void dumpVal(std::string& out, const char* name, const std::string& valueName, E dumpVal(out, name, valueName, static_cast>(value)); } -void dumpVal(std::string& out, const char* name, const FloatRect& rect); -void dumpVal(std::string& out, const char* name, const Rect& rect); -void dumpVal(std::string& out, const char* name, const Region& region); -void dumpVal(std::string& out, const char* name, const ui::Transform&); -void dumpVal(std::string& out, const char* name, const ui::Size&); +void dumpVal(std::string& out, const char* name, ui::LayerFilter); +void dumpVal(std::string& out, const char* name, ui::Size); -void dumpVal(std::string& out, const char* name, const mat4& tr); +void dumpVal(std::string& out, const char* name, const FloatRect&); +void dumpVal(std::string& out, const char* name, const Rect&); +void dumpVal(std::string& out, const char* name, const Region&); +void dumpVal(std::string& out, const char* name, const ui::Transform&); +void dumpVal(std::string& out, const char* name, const mat4&); void dumpVal(std::string& out, const char* name, const StretchEffect&); } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 14f2163f52..cb9426c73d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -23,6 +23,7 @@ #include #include #include + #include #include #include @@ -45,7 +46,7 @@ public: void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) override; void setDisplaySize(const ui::Size&) override; - void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override; + void setLayerFilter(ui::LayerFilter) override; ui::Transform::RotationFlags getTransformHint() const override; void setColorTransform(const compositionengine::CompositionRefreshArgs&) override; @@ -65,8 +66,9 @@ public: void setRenderSurface(std::unique_ptr) override; Region getDirtyRegion(bool repaintEverything) const override; - bool belongsInOutput(std::optional, bool) const override; - bool belongsInOutput(const sp&) const override; + + bool includesLayer(ui::LayerFilter) const override; + bool includesLayer(const sp&) const override; compositionengine::OutputLayer* getOutputLayerForLayer(const sp&) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index f34cb94079..44f754f936 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -32,6 +32,7 @@ #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include +#include #include #include #include @@ -59,11 +60,8 @@ struct OutputCompositionState { // If true, the current frame reused the buffer from a previous client composition bool reusedClientComposition{false}; - // If true, this output displays layers that are internal-only - bool layerStackInternal{false}; - - // The layer stack to display on this display - uint32_t layerStackId{~0u}; + // The conditions for including a layer on this output + ui::LayerFilter layerFilter; // The common space for all layers in the layer stack. layerStackSpace.content is the Rect // which gets projected on the display. The orientation of this space is always ROTATION_0. diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 216019fd1d..58627da828 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -40,9 +40,12 @@ public: MOCK_METHOD1(setLayerCachingTexturePoolEnabled, void(bool)); MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&)); MOCK_METHOD1(setDisplaySize, void(const ui::Size&)); - MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool)); MOCK_CONST_METHOD0(getTransformHint, ui::Transform::RotationFlags()); + MOCK_METHOD(void, setLayerFilter, (ui::LayerFilter)); + MOCK_METHOD(bool, includesLayer, (ui::LayerFilter), (const)); + MOCK_METHOD(bool, includesLayer, (const sp&), (const)); + MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD1(setColorProfile, void(const ColorProfile&)); MOCK_METHOD2(setDisplayBrightness, void(float, float)); @@ -63,8 +66,6 @@ public: MOCK_METHOD0(editState, OutputCompositionState&()); MOCK_CONST_METHOD1(getDirtyRegion, Region(bool)); - MOCK_CONST_METHOD2(belongsInOutput, bool(std::optional, bool)); - MOCK_CONST_METHOD1(belongsInOutput, bool(const sp&)); MOCK_CONST_METHOD1(getOutputLayerForLayer, compositionengine::OutputLayer*(const sp&)); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 2f2c686805..2cc5faef33 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -51,12 +51,9 @@ Display::~Display() = default; void Display::setConfiguration(const compositionengine::DisplayCreationArgs& args) { mId = args.id; - mIsVirtual = !args.connectionType; mPowerAdvisor = args.powerAdvisor; editState().isSecure = args.isSecure; editState().displaySpace.bounds = Rect(args.pixels); - setLayerStackFilter(args.layerStackId, - args.connectionType == ui::DisplayConnectionType::Internal); setName(args.name); } @@ -73,7 +70,7 @@ bool Display::isSecure() const { } bool Display::isVirtual() const { - return mIsVirtual; + return VirtualDisplayId::tryCast(mId).has_value(); } std::optional Display::getDisplayId() const { @@ -117,8 +114,8 @@ void Display::setColorProfile(const ColorProfile& colorProfile) { return; } - if (mIsVirtual) { - ALOGW("%s: Invalid operation on virtual display", __FUNCTION__); + if (isVirtual()) { + ALOGW("%s: Invalid operation on virtual display", __func__); return; } @@ -136,7 +133,7 @@ void Display::dump(std::string& out) const { StringAppendF(&out, " Composition Display State: [\"%s\"]", getName().c_str()); out.append("\n "); - dumpVal(out, "isVirtual", mIsVirtual); + dumpVal(out, "isVirtual", isVirtual()); dumpVal(out, "DisplayId", to_string(mId)); out.append("\n"); diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp index 5565396922..01c368de88 100644 --- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp @@ -63,6 +63,18 @@ void dumpVal(std::string& out, const char* name, const std::string& valueName, i dumpVal(out, name, valueName.c_str(), value); } +void dumpVal(std::string& out, const char* name, ui::LayerFilter filter) { + out.append(name); + out.append("={"); + dumpVal(out, "layerStack", filter.layerStack.id); + dumpVal(out, "toInternalDisplay", filter.toInternalDisplay); + out.push_back('}'); +} + +void dumpVal(std::string& out, const char* name, ui::Size size) { + StringAppendF(&out, "%s=[%d %d] ", name, size.width, size.height); +} + void dumpVal(std::string& out, const char* name, const FloatRect& rect) { StringAppendF(&out, "%s=[%f %f %f %f] ", name, rect.left, rect.top, rect.right, rect.bottom); } @@ -80,10 +92,6 @@ void dumpVal(std::string& out, const char* name, const ui::Transform& transform) out.append(" "); } -void dumpVal(std::string& out, const char* name, const ui::Size& size) { - StringAppendF(&out, "%s=[%d %d] ", name, size.width, size.height); -} - void dumpVal(std::string& out, const char* name, const mat4& tr) { StringAppendF(&out, "%s=[" diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 6ac488be29..5e40802e93 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -227,11 +227,8 @@ ui::Transform::RotationFlags Output::getTransformHint() const { return static_cast(getState().transform.getOrientation()); } -void Output::setLayerStackFilter(uint32_t layerStackId, bool isInternal) { - auto& outputState = editState(); - outputState.layerStackId = layerStackId; - outputState.layerStackInternal = isInternal; - +void Output::setLayerFilter(ui::LayerFilter filter) { + editState().layerFilter = filter; dirtyEntireOutput(); } @@ -380,17 +377,13 @@ Region Output::getDirtyRegion(bool repaintEverything) const { return dirty; } -bool Output::belongsInOutput(std::optional layerStackId, bool internalOnly) const { - // The layerStackId's must match, and also the layer must not be internal - // only when not on an internal output. - const auto& outputState = getState(); - return layerStackId && (*layerStackId == outputState.layerStackId) && - (!internalOnly || outputState.layerStackInternal); +bool Output::includesLayer(ui::LayerFilter filter) const { + return getState().layerFilter.includes(filter); } -bool Output::belongsInOutput(const sp& layerFE) const { +bool Output::includesLayer(const sp& layerFE) const { const auto* layerFEState = layerFE->getCompositionState(); - return layerFEState && belongsInOutput(layerFEState->layerStackId, layerFEState->internalOnly); + return layerFEState && includesLayer(layerFEState->outputFilter); } std::unique_ptr Output::createOutputLayer( @@ -496,8 +489,8 @@ void Output::ensureOutputLayerIfVisible(sp& layerFE, layerFE->prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry); } - // Only consider the layers on the given layer stack - if (!belongsInOutput(layerFE)) { + // Only consider the layers on this output + if (!includesLayer(layerFE)) { return; } @@ -1122,7 +1115,7 @@ std::optional Output::composeSurfaces( // bounds its framebuffer cache but Skia RenderEngine has no current policy. The best fix is // probably to encapsulate the output buffer into a structure that dispatches resource cleanup // over to RenderEngine, in which case this flag can be removed from the drawLayers interface. - const bool useFramebufferCache = outputState.layerStackInternal; + const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay; status_t status = renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex, useFramebufferCache, std::move(fd), &readyFence); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index ee30ad8583..acc92162ac 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -28,9 +28,7 @@ void OutputCompositionState::dump(std::string& out) const { dumpVal(out, "usesDeviceComposition", usesDeviceComposition); dumpVal(out, "flipClientTarget", flipClientTarget); dumpVal(out, "reusedClientComposition", reusedClientComposition); - - dumpVal(out, "layerStack", layerStackId); - dumpVal(out, "layerStackInternal", layerStackInternal); + dumpVal(out, "layerFilter", layerFilter); out.append("\n "); diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 72b16e0741..543dde1ca0 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -61,7 +61,6 @@ constexpr HalVirtualDisplayId HAL_VIRTUAL_DISPLAY_ID{456u}; constexpr GpuVirtualDisplayId GPU_VIRTUAL_DISPLAY_ID{789u}; constexpr ui::Size DEFAULT_RESOLUTION{1920, 1080}; -constexpr uint32_t DEFAULT_LAYER_STACK = 42; struct Layer { Layer() { @@ -161,13 +160,11 @@ struct DisplayTestCommon : public testing::Test { EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false)); } - DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() { + DisplayCreationArgs getDisplayCreationArgsForPhysicalDisplay() { return DisplayCreationArgsBuilder() .setId(DEFAULT_DISPLAY_ID) - .setConnectionType(ui::DisplayConnectionType::Internal) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(true) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .build(); } @@ -177,7 +174,6 @@ struct DisplayTestCommon : public testing::Test { .setId(GPU_VIRTUAL_DISPLAY_ID) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .build(); } @@ -193,14 +189,13 @@ struct PartialMockDisplayTestCommon : public DisplayTestCommon { using Display = DisplayTestCommon::PartialMockDisplay; std::shared_ptr mDisplay = createPartialMockDisplay(mCompositionEngine, - getDisplayCreationArgsForPhysicalHWCDisplay()); + getDisplayCreationArgsForPhysicalDisplay()); }; struct FullDisplayImplTestCommon : public DisplayTestCommon { using Display = DisplayTestCommon::FullImplDisplay; std::shared_ptr mDisplay = - createDisplay(mCompositionEngine, - getDisplayCreationArgsForPhysicalHWCDisplay()); + createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay()); }; struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon { @@ -218,8 +213,7 @@ struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon { LayerNoHWC2Layer mLayer3; StrictMock hwc2LayerUnknown; std::shared_ptr mDisplay = - createDisplay(mCompositionEngine, - getDisplayCreationArgsForPhysicalHWCDisplay()); + createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay()); }; /* @@ -232,7 +226,7 @@ struct DisplayCreationTest : public DisplayTestCommon { TEST_F(DisplayCreationTest, createPhysicalInternalDisplay) { auto display = - impl::createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalHWCDisplay()); + impl::createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay()); EXPECT_TRUE(display->isSecure()); EXPECT_FALSE(display->isVirtual()); EXPECT_EQ(DEFAULT_DISPLAY_ID, display->getId()); @@ -252,13 +246,11 @@ TEST_F(DisplayCreationTest, createGpuVirtualDisplay) { using DisplaySetConfigurationTest = PartialMockDisplayTestCommon; -TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) { +TEST_F(DisplaySetConfigurationTest, configuresPhysicalDisplay) { mDisplay->setConfiguration(DisplayCreationArgsBuilder() .setId(DEFAULT_DISPLAY_ID) - .setConnectionType(ui::DisplayConnectionType::Internal) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(true) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .setName(getDisplayNameFromCurrentTest()) .build()); @@ -266,28 +258,11 @@ TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) { EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId()); EXPECT_TRUE(mDisplay->isSecure()); EXPECT_FALSE(mDisplay->isVirtual()); - EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); - EXPECT_TRUE(mDisplay->getState().layerStackInternal); EXPECT_FALSE(mDisplay->isValid()); -} -TEST_F(DisplaySetConfigurationTest, configuresExternalInsecurePhysicalDisplay) { - mDisplay->setConfiguration(DisplayCreationArgsBuilder() - .setId(DEFAULT_DISPLAY_ID) - .setConnectionType(ui::DisplayConnectionType::External) - .setPixels(DEFAULT_RESOLUTION) - .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) - .setPowerAdvisor(&mPowerAdvisor) - .setName(getDisplayNameFromCurrentTest()) - .build()); - - EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId()); - EXPECT_FALSE(mDisplay->isSecure()); - EXPECT_FALSE(mDisplay->isVirtual()); - EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); - EXPECT_FALSE(mDisplay->getState().layerStackInternal); - EXPECT_FALSE(mDisplay->isValid()); + const auto& filter = mDisplay->getState().layerFilter; + EXPECT_EQ(ui::INVALID_LAYER_STACK, filter.layerStack); + EXPECT_FALSE(filter.toInternalDisplay); } TEST_F(DisplaySetConfigurationTest, configuresHalVirtualDisplay) { @@ -295,7 +270,6 @@ TEST_F(DisplaySetConfigurationTest, configuresHalVirtualDisplay) { .setId(HAL_VIRTUAL_DISPLAY_ID) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .setName(getDisplayNameFromCurrentTest()) .build()); @@ -303,9 +277,11 @@ TEST_F(DisplaySetConfigurationTest, configuresHalVirtualDisplay) { EXPECT_EQ(HAL_VIRTUAL_DISPLAY_ID, mDisplay->getId()); EXPECT_FALSE(mDisplay->isSecure()); EXPECT_TRUE(mDisplay->isVirtual()); - EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); - EXPECT_FALSE(mDisplay->getState().layerStackInternal); EXPECT_FALSE(mDisplay->isValid()); + + const auto& filter = mDisplay->getState().layerFilter; + EXPECT_EQ(ui::INVALID_LAYER_STACK, filter.layerStack); + EXPECT_FALSE(filter.toInternalDisplay); } TEST_F(DisplaySetConfigurationTest, configuresGpuVirtualDisplay) { @@ -313,7 +289,6 @@ TEST_F(DisplaySetConfigurationTest, configuresGpuVirtualDisplay) { .setId(GPU_VIRTUAL_DISPLAY_ID) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .setName(getDisplayNameFromCurrentTest()) .build()); @@ -321,9 +296,11 @@ TEST_F(DisplaySetConfigurationTest, configuresGpuVirtualDisplay) { EXPECT_EQ(GPU_VIRTUAL_DISPLAY_ID, mDisplay->getId()); EXPECT_FALSE(mDisplay->isSecure()); EXPECT_TRUE(mDisplay->isVirtual()); - EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); - EXPECT_FALSE(mDisplay->getState().layerStackInternal); EXPECT_FALSE(mDisplay->isValid()); + + const auto& filter = mDisplay->getState().layerFilter; + EXPECT_EQ(ui::INVALID_LAYER_STACK, filter.layerStack); + EXPECT_FALSE(filter.toInternalDisplay); } /* @@ -998,10 +975,8 @@ struct DisplayFunctionalTest : public testing::Test { Display>(mCompositionEngine, DisplayCreationArgsBuilder() .setId(DEFAULT_DISPLAY_ID) - .setConnectionType(ui::DisplayConnectionType::Internal) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(true) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .build()); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index c3185e9e7e..e7fad594a6 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -403,17 +403,18 @@ TEST_F(OutputTest, setDisplaySpaceSizeUpdatesOutputStateAndDirtiesEntireOutput) } /* - * Output::setLayerStackFilter() + * Output::setLayerFilter() */ -TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) { - const uint32_t layerStack = 123u; - mOutput->setLayerStackFilter(layerStack, true); +TEST_F(OutputTest, setLayerFilterSetsFilterAndDirtiesEntireOutput) { + constexpr ui::LayerFilter kFilter{ui::LayerStack{123u}, true}; + mOutput->setLayerFilter(kFilter); - EXPECT_TRUE(mOutput->getState().layerStackInternal); - EXPECT_EQ(layerStack, mOutput->getState().layerStackId); + const auto& state = mOutput->getState(); + EXPECT_EQ(kFilter.layerStack, state.layerFilter.layerStack); + EXPECT_TRUE(state.layerFilter.toInternalDisplay); - EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); + EXPECT_THAT(state.dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } /* @@ -593,100 +594,90 @@ TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) { } /* - * Output::belongsInOutput() + * Output::includesLayer() */ -TEST_F(OutputTest, belongsInOutputFiltersAsExpected) { - const uint32_t layerStack1 = 123u; - const uint32_t layerStack2 = 456u; +TEST_F(OutputTest, layerFiltering) { + const ui::LayerStack layerStack1{123u}; + const ui::LayerStack layerStack2{456u}; - // If the output accepts layerStack1 and internal-only layers.... - mOutput->setLayerStackFilter(layerStack1, true); + // If the output is associated to layerStack1 and to an internal display... + mOutput->setLayerFilter({layerStack1, true}); - // A layer with no layerStack does not belong to it, internal-only or not. - EXPECT_FALSE(mOutput->belongsInOutput(std::nullopt, false)); - EXPECT_FALSE(mOutput->belongsInOutput(std::nullopt, true)); + // It excludes layers with no layer stack, internal-only or not. + EXPECT_FALSE(mOutput->includesLayer({ui::INVALID_LAYER_STACK, false})); + EXPECT_FALSE(mOutput->includesLayer({ui::INVALID_LAYER_STACK, true})); - // Any layer with layerStack1 belongs to it, internal-only or not. - EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, false)); - EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, true)); - EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, true)); - EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, false)); + // It includes layers on layerStack1, internal-only or not. + EXPECT_TRUE(mOutput->includesLayer({layerStack1, false})); + EXPECT_TRUE(mOutput->includesLayer({layerStack1, true})); + EXPECT_FALSE(mOutput->includesLayer({layerStack2, true})); + EXPECT_FALSE(mOutput->includesLayer({layerStack2, false})); - // If the output accepts layerStack21 but not internal-only layers... - mOutput->setLayerStackFilter(layerStack1, false); + // If the output is associated to layerStack1 but not to an internal display... + mOutput->setLayerFilter({layerStack1, false}); - // Only non-internal layers with layerStack1 belong to it. - EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, false)); - EXPECT_FALSE(mOutput->belongsInOutput(layerStack1, true)); - EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, true)); - EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, false)); + // It includes layers on layerStack1, unless they are internal-only. + EXPECT_TRUE(mOutput->includesLayer({layerStack1, false})); + EXPECT_FALSE(mOutput->includesLayer({layerStack1, true})); + EXPECT_FALSE(mOutput->includesLayer({layerStack2, true})); + EXPECT_FALSE(mOutput->includesLayer({layerStack2, false})); } -TEST_F(OutputTest, belongsInOutputHandlesLayerWithNoCompositionState) { +TEST_F(OutputTest, layerFilteringWithoutCompositionState) { NonInjectedLayer layer; sp layerFE(layer.layerFE); - // If the layer has no composition state, it does not belong to any output. + // Layers without composition state are excluded. EXPECT_CALL(*layer.layerFE, getCompositionState).WillOnce(Return(nullptr)); - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + EXPECT_FALSE(mOutput->includesLayer(layerFE)); } -TEST_F(OutputTest, belongsInOutputFiltersLayersAsExpected) { +TEST_F(OutputTest, layerFilteringWithCompositionState) { NonInjectedLayer layer; sp layerFE(layer.layerFE); - const uint32_t layerStack1 = 123u; - const uint32_t layerStack2 = 456u; + const ui::LayerStack layerStack1{123u}; + const ui::LayerStack layerStack2{456u}; - // If the output accepts layerStack1 and internal-only layers.... - mOutput->setLayerStackFilter(layerStack1, true); + // If the output is associated to layerStack1 and to an internal display... + mOutput->setLayerFilter({layerStack1, true}); - // A layer with no layerStack does not belong to it, internal-only or not. - layer.layerFEState.layerStackId = std::nullopt; - layer.layerFEState.internalOnly = false; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + // It excludes layers with no layer stack, internal-only or not. + layer.layerFEState.outputFilter = {ui::INVALID_LAYER_STACK, false}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = std::nullopt; - layer.layerFEState.internalOnly = true; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {ui::INVALID_LAYER_STACK, true}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); - // Any layer with layerStack1 belongs to it, internal-only or not. - layer.layerFEState.layerStackId = layerStack1; - layer.layerFEState.internalOnly = false; - EXPECT_TRUE(mOutput->belongsInOutput(layerFE)); + // It includes layers on layerStack1, internal-only or not. + layer.layerFEState.outputFilter = {layerStack1, false}; + EXPECT_TRUE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = layerStack1; - layer.layerFEState.internalOnly = true; - EXPECT_TRUE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {layerStack1, true}; + EXPECT_TRUE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = layerStack2; - layer.layerFEState.internalOnly = true; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {layerStack2, true}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = layerStack2; - layer.layerFEState.internalOnly = false; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {layerStack2, false}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); - // If the output accepts layerStack1 but not internal-only layers... - mOutput->setLayerStackFilter(layerStack1, false); + // If the output is associated to layerStack1 but not to an internal display... + mOutput->setLayerFilter({layerStack1, false}); - // Only non-internal layers with layerStack1 belong to it. - layer.layerFEState.layerStackId = layerStack1; - layer.layerFEState.internalOnly = false; - EXPECT_TRUE(mOutput->belongsInOutput(layerFE)); + // It includes layers on layerStack1, unless they are internal-only. + layer.layerFEState.outputFilter = {layerStack1, false}; + EXPECT_TRUE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = layerStack1; - layer.layerFEState.internalOnly = true; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {layerStack1, true}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = layerStack2; - layer.layerFEState.internalOnly = true; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {layerStack2, true}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = layerStack2; - layer.layerFEState.internalOnly = false; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {layerStack2, false}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); } /* @@ -1268,14 +1259,15 @@ struct OutputEnsureOutputLayerIfVisibleTest : public testing::Test { struct OutputPartialMock : public OutputPartialMockBase { // Sets up the helper functions called by the function under test to use // mock implementations. - MOCK_CONST_METHOD1(belongsInOutput, bool(const sp&)); + MOCK_METHOD(bool, includesLayer, (const sp&), + (const, override)); MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex, OutputLayer*(size_t)); MOCK_METHOD2(ensureOutputLayer, compositionengine::OutputLayer*(std::optional, const sp&)); }; OutputEnsureOutputLayerIfVisibleTest() { - EXPECT_CALL(mOutput, belongsInOutput(sp(mLayer.layerFE))) + EXPECT_CALL(mOutput, includesLayer(sp(mLayer.layerFE))) .WillRepeatedly(Return(true)); EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u)); EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u)) @@ -1326,8 +1318,8 @@ const Region OutputEnsureOutputLayerIfVisibleTest::kLowerHalfBoundsNoRotation = const Region OutputEnsureOutputLayerIfVisibleTest::kFullBounds90Rotation = Region(Rect(0, 0, 200, 100)); -TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerBelongs) { - EXPECT_CALL(mOutput, belongsInOutput(sp(mLayer.layerFE))).WillOnce(Return(false)); +TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerIncluded) { + EXPECT_CALL(mOutput, includesLayer(sp(mLayer.layerFE))).WillOnce(Return(false)); EXPECT_CALL(*mLayer.layerFE, prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry)); @@ -1337,8 +1329,8 @@ TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLa } TEST_F(OutputEnsureOutputLayerIfVisibleTest, - skipsLatchIfAlreadyLatchedBeforeCheckingIfLayerBelongs) { - EXPECT_CALL(mOutput, belongsInOutput(sp(mLayer.layerFE))).WillOnce(Return(false)); + skipsLatchIfAlreadyLatchedBeforeCheckingIfLayerIncluded) { + EXPECT_CALL(mOutput, includesLayer(sp(mLayer.layerFE))).WillOnce(Return(false)); ensureOutputLayerIfVisible(); } @@ -3188,8 +3180,7 @@ TEST_F(OutputComposeSurfacesTest, r1.geometry.boundaries = FloatRect{1, 2, 3, 4}; r2.geometry.boundaries = FloatRect{5, 6, 7, 8}; - const constexpr uint32_t kInternalLayerStack = 1234; - mOutput.setLayerStackFilter(kInternalLayerStack, true); + mOutput.setLayerFilter({ui::LayerStack{1234u}, true}); EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false)); EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true)); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 4445eea604..802a17d981 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -232,7 +232,7 @@ ui::Dataspace DisplayDevice::getCompositionDataSpace() const { } void DisplayDevice::setLayerStack(ui::LayerStack stack) { - mCompositionDisplay->setLayerStackFilter(stack, isInternal()); + mCompositionDisplay->setLayerFilter({stack, isInternal()}); if (mRefreshRateOverlay) { mRefreshRateOverlay->setLayerStack(stack); } @@ -349,7 +349,7 @@ bool DisplayDevice::needsFiltering() const { } ui::LayerStack DisplayDevice::getLayerStack() const { - return mCompositionDisplay->getState().layerStackId; + return mCompositionDisplay->getState().layerFilter.layerStack; } ui::Transform::RotationFlags DisplayDevice::getTransformHint() const { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 7db87d9123..43a6bd540a 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -86,9 +86,7 @@ public: bool isVirtual() const { return !mConnectionType; } bool isPrimary() const { return mIsPrimary; } - bool isInternal() const { - return !isVirtual() && mConnectionType == ui::DisplayConnectionType::Internal; - } + bool isInternal() const { return mConnectionType == ui::DisplayConnectionType::Internal; } // isSecure indicates whether this display can be trusted to display // secure surfaces. @@ -311,7 +309,7 @@ struct DisplayDeviceState { int32_t sequenceId = sNextSequenceId++; std::optional physical; sp surface; - ui::LayerStack layerStack = ui::NO_LAYER_STACK; + ui::LayerStack layerStack; uint32_t flags = 0; Rect layerStackSpaceRect; Rect orientedDisplaySpaceRect; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 28c8213fc9..51568547b4 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -107,7 +107,7 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.requestedCrop = mDrawingState.crop; mDrawingState.z = 0; mDrawingState.color.a = 1.0f; - mDrawingState.layerStack = 0; + mDrawingState.layerStack = ui::DEFAULT_LAYER_STACK; mDrawingState.sequence = 0; mDrawingState.requested_legacy = mDrawingState.active_legacy; mDrawingState.width = UINT32_MAX; @@ -391,7 +391,6 @@ void Layer::setupRoundedCornersCropCoordinates(Rect win, void Layer::prepareBasicGeometryCompositionState() { const auto& drawingState{getDrawingState()}; - const uint32_t layerStack = getLayerStack(); const auto alpha = static_cast(getAlpha()); const bool opaque = isOpaque(drawingState); const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f; @@ -403,9 +402,7 @@ void Layer::prepareBasicGeometryCompositionState() { } auto* compositionState = editCompositionState(); - compositionState->layerStackId = - (layerStack != ~0u) ? std::make_optional(layerStack) : std::nullopt; - compositionState->internalOnly = getPrimaryDisplayOnly(); + compositionState->outputFilter = getOutputFilter(); compositionState->isVisible = isVisible(); compositionState->isOpaque = opaque && !usesRoundedCorners && alpha == 1.f; compositionState->shadowRadius = mEffectiveShadowRadius; @@ -1005,7 +1002,7 @@ bool Layer::setMetadata(const LayerMetadata& data) { return true; } -bool Layer::setLayerStack(uint32_t layerStack) { +bool Layer::setLayerStack(ui::LayerStack layerStack) { if (mDrawingState.layerStack == layerStack) return false; mDrawingState.sequence++; mDrawingState.layerStack = layerStack; @@ -1052,12 +1049,11 @@ bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) { return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE; }; -uint32_t Layer::getLayerStack() const { - auto p = mDrawingParent.promote(); - if (p == nullptr) { - return getDrawingState().layerStack; +ui::LayerStack Layer::getLayerStack() const { + if (const auto parent = mDrawingParent.promote()) { + return parent->getLayerStack(); } - return p->getLayerStack(); + return getDrawingState().layerStack; } bool Layer::setShadowRadius(float shadowRadius) { @@ -1371,7 +1367,7 @@ LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const { info.mVisibleRegion = getVisibleRegion(display); info.mSurfaceDamageRegion = surfaceDamageRegion; - info.mLayerStack = getLayerStack(); + info.mLayerStack = getLayerStack().id; info.mX = ds.transform.tx(); info.mY = ds.transform.ty(); info.mZ = ds.z; @@ -2087,7 +2083,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy, [&]() { return layerInfo->mutable_transparent_region(); }); - layerInfo->set_layer_stack(getLayerStack()); + layerInfo->set_layer_stack(getLayerStack().id); layerInfo->set_z(state.z); LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), @@ -2134,7 +2130,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet if (traceFlags & SurfaceTracing::TRACE_INPUT) { WindowInfo info; if (useDrawing) { - info = fillInputInfo({nullptr}); + info = fillInputInfo(nullptr); } else { info = state.inputInfo; } @@ -2163,7 +2159,7 @@ Rect Layer::getInputBounds() const { return getCroppedBufferSize(getDrawingState()); } -void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& toPhysicalDisplay) { +void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTransform) { // Transform layer size to screen space and inset it by surface insets. // If this is a portal window, set the touchableRegion to the layerBounds. Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE @@ -2183,13 +2179,13 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& toPhysical return; } - ui::Transform layerToDisplay = getInputTransform(); + const ui::Transform layerTransform = getInputTransform(); // Transform that takes window coordinates to unrotated display coordinates - ui::Transform t = toPhysicalDisplay * layerToDisplay; + ui::Transform t = displayTransform * layerTransform; int32_t xSurfaceInset = info.surfaceInset; int32_t ySurfaceInset = info.surfaceInset; // Bring screenBounds into unrotated space - Rect screenBounds = toPhysicalDisplay.transform(Rect{mScreenBounds}); + Rect screenBounds = displayTransform.transform(Rect{mScreenBounds}); const float xScale = t.getScaleX(); const float yScale = t.getScaleY(); @@ -2268,33 +2264,33 @@ void Layer::fillTouchOcclusionMode(WindowInfo& info) { } } -WindowInfo Layer::fillInputInfo(const sp& display) { +WindowInfo Layer::fillInputInfo(const DisplayDevice* display) { if (!hasInputInfo()) { mDrawingState.inputInfo.name = getName(); mDrawingState.inputInfo.ownerUid = mOwnerUid; mDrawingState.inputInfo.ownerPid = mOwnerPid; mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL; mDrawingState.inputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL; - mDrawingState.inputInfo.displayId = getLayerStack(); + mDrawingState.inputInfo.displayId = getLayerStack().id; } WindowInfo info = mDrawingState.inputInfo; info.id = sequence; - info.displayId = getLayerStack(); + info.displayId = getLayerStack().id; - // Transform that goes from "logical(rotated)" display to physical/unrotated display. - // This is for when inputflinger operates in physical display-space. - ui::Transform toPhysicalDisplay; + // Transform that maps from LayerStack space to display space, e.g. rotated to unrotated. + // Used when InputFlinger operates in display space. + ui::Transform displayTransform; if (display) { - toPhysicalDisplay = display->getTransform(); + displayTransform = display->getTransform(); // getOrientation() without masking can contain more-significant bits (eg. ROT_INVALID). - static constexpr uint32_t ALL_ROTATIONS_MASK = + constexpr uint32_t kAllRotationsMask = ui::Transform::ROT_90 | ui::Transform::ROT_180 | ui::Transform::ROT_270; - info.displayOrientation = toPhysicalDisplay.getOrientation() & ALL_ROTATIONS_MASK; + info.displayOrientation = displayTransform.getOrientation() & kAllRotationsMask; info.displayWidth = display->getWidth(); info.displayHeight = display->getHeight(); } - fillInputFrameInfo(info, toPhysicalDisplay); + fillInputFrameInfo(info, displayTransform); // For compatibility reasons we let layers which can receive input // receive input before they have actually submitted a buffer. Because @@ -2310,15 +2306,11 @@ WindowInfo Layer::fillInputInfo(const sp& display) { auto cropLayer = mDrawingState.touchableRegionCrop.promote(); if (info.replaceTouchableRegionWithCrop) { - if (cropLayer == nullptr) { - info.touchableRegion = Region(toPhysicalDisplay.transform(Rect{mScreenBounds})); - } else { - info.touchableRegion = - Region(toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds})); - } + const Rect bounds(cropLayer ? cropLayer->mScreenBounds : mScreenBounds); + info.touchableRegion = Region(displayTransform.transform(bounds)); } else if (cropLayer != nullptr) { info.touchableRegion = info.touchableRegion.intersect( - toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds})); + displayTransform.transform(Rect{cropLayer->mScreenBounds})); } // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state @@ -2329,9 +2321,8 @@ WindowInfo Layer::fillInputInfo(const sp& display) { // If the layer is a clone, we need to crop the input region to cloned root to prevent // touches from going outside the cloned area. if (isClone()) { - sp clonedRoot = getClonedRoot(); - if (clonedRoot != nullptr) { - Rect rect = toPhysicalDisplay.transform(Rect{clonedRoot->mScreenBounds}); + if (const sp clonedRoot = getClonedRoot()) { + const Rect rect = displayTransform.transform(Rect{clonedRoot->mScreenBounds}); info.touchableRegion = info.touchableRegion.intersect(rect); } } @@ -2527,14 +2518,14 @@ scheduler::Seamlessness Layer::FrameRate::convertChangeFrameRateStrategy(int8_t } } -bool Layer::getPrimaryDisplayOnly() const { +bool Layer::isInternalDisplayOverlay() const { const State& s(mDrawingState); if (s.flags & layer_state_t::eLayerSkipScreenshot) { return true; } sp parent = mDrawingParent.promote(); - return parent == nullptr ? false : parent->getPrimaryDisplayOnly(); + return parent && parent->isInternalDisplayOverlay(); } void Layer::setClonedChild(const sp& clonedChild) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 41bdebdf10..982f246b00 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -151,12 +151,7 @@ public: Geometry requested_legacy; int32_t z; - // The identifier of the layer stack this layer belongs to. A layer can - // only be associated to a single layer stack. A layer stack is a - // z-ordered group of layers which can be associated to one or more - // displays. Using the same layer stack on different displays is a way - // to achieve mirroring. - uint32_t layerStack; + ui::LayerStack layerStack; uint32_t flags; uint8_t reserved[2]; @@ -403,8 +398,8 @@ public: virtual bool setTransparentRegionHint(const Region& transparent); virtual bool setTrustedOverlay(bool); virtual bool setFlags(uint32_t flags, uint32_t mask); - virtual bool setLayerStack(uint32_t layerStack); - virtual uint32_t getLayerStack() const; + virtual bool setLayerStack(ui::LayerStack); + virtual ui::LayerStack getLayerStack() const; virtual bool setMetadata(const LayerMetadata& data); virtual void setChildrenDrawingParent(const sp&); virtual bool reparent(const sp& newParentHandle); @@ -645,11 +640,6 @@ public: uint32_t getTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); - // Deprecated, please use compositionengine::Output::belongsInOutput() - // instead. - // TODO(lpique): Move the remaining callers (screencap) to the new function. - bool belongsToDisplay(uint32_t layerStack) const { return getLayerStack() == layerStack; } - FloatRect getBounds(const Region& activeTransparentRegion) const; FloatRect getBounds() const; @@ -681,6 +671,14 @@ public: */ bool isHiddenByPolicy() const; + // True if the layer should be skipped in screenshots, screen recordings, + // and mirroring to external or virtual displays. + bool isInternalDisplayOverlay() const; + + ui::LayerFilter getOutputFilter() const { + return {getLayerStack(), isInternalDisplayOverlay()}; + } + bool isRemovedFromCurrentState() const; LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags, const DisplayDevice*); @@ -697,8 +695,6 @@ public: gui::WindowInfo::Type getWindowType() const { return mWindowType; } - bool getPrimaryDisplayOnly() const; - void updateMirrorInfo(); /* @@ -848,7 +844,8 @@ public: bool getPremultipledAlpha() const; void setInputInfo(const gui::WindowInfo& info); - gui::WindowInfo fillInputInfo(const sp& display); + gui::WindowInfo fillInputInfo(const DisplayDevice*); + /** * Returns whether this layer has an explicitly set input-info. */ @@ -1069,8 +1066,8 @@ private: // hasInputInfo() or no-op if no such parent is found. void fillTouchOcclusionMode(gui::WindowInfo& info); - // Fills in the frame and transform info for the gui::WindowInfo - void fillInputFrameInfo(gui::WindowInfo& info, const ui::Transform& toPhysicalDisplay); + // Fills in the frame and transform info for the gui::WindowInfo. + void fillInputFrameInfo(gui::WindowInfo&, const ui::Transform& displayTransform); // Cached properties computed from drawing state // Effective transform taking into account parent transforms and any parent scaling, which is diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp index aee820a88c..f52e60deda 100644 --- a/services/surfaceflinger/LayerVector.cpp +++ b/services/surfaceflinger/LayerVector.cpp @@ -45,8 +45,8 @@ int LayerVector::do_compare(const void* lhs, const void* rhs) const const auto& lState = l->getDrawingState(); const auto& rState = r->getDrawingState(); - uint32_t ls = lState.layerStack; - uint32_t rs = rState.layerStack; + const auto ls = lState.layerStack; + const auto rs = rState.layerStack; if (ls != rs) return (ls > rs) ? 1 : -1; diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 2adfe14ef7..40d4c61401 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -281,7 +281,7 @@ void RefreshRateOverlay::setViewport(ui::Size viewport) { mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } -void RefreshRateOverlay::setLayerStack(uint32_t stack) { +void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) { mLayer->setLayerStack(stack); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index fd1e2df96d..63ae383c8c 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -41,7 +42,7 @@ class RefreshRateOverlay { public: RefreshRateOverlay(SurfaceFlinger&, uint32_t lowFps, uint32_t highFps, bool showSpinner); - void setLayerStack(uint32_t stack); + void setLayerStack(ui::LayerStack); void setViewport(ui::Size); void changeRefreshRate(const Fps&); void onInvalidate(); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 99d9bb3463..417bffc998 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2295,7 +2295,7 @@ void SurfaceFlinger::postComposition() { int32_t maxArea = 0; mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) { const auto layerFe = layer->getCompositionEngineLayerFE(); - if (layer->isVisible() && compositionDisplay->belongsInOutput(layerFe)) { + if (layer->isVisible() && compositionDisplay->includesLayer(layerFe)) { const Dataspace transfer = static_cast(layer->getDataSpace() & Dataspace::TRANSFER_MASK); const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 || @@ -2426,8 +2426,8 @@ void SurfaceFlinger::computeLayerBounds() { const auto& displayDevice = pair.second; const auto display = displayDevice->getCompositionDisplay(); for (const auto& layer : mDrawingState.layersSortedByZ) { - // only consider the layers on the given layer stack - if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) { + // Only consider the layers on this display. + if (!display->includesLayer(layer->getOutputFilter())) { continue; } @@ -2732,14 +2732,12 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, compositionengine::DisplayCreationArgsBuilder builder; if (const auto& physical = state.physical) { builder.setId(physical->id); - builder.setConnectionType(physical->type); } else { builder.setId(acquireVirtualDisplay(resolution, pixelFormat)); } builder.setPixels(resolution); builder.setIsSecure(state.isSecure); - builder.setLayerStackId(state.layerStack); builder.setPowerAdvisor(&mPowerAdvisor); builder.setName(state.displayName); auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); @@ -2942,16 +2940,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { // Update transform hint if (transactionFlags & (eTransformHintUpdateNeeded | eDisplayTransactionNeeded)) { - // The transform hint might have changed for some layers - // (either because a display has changed, or because a layer - // as changed). - // - // Walk through all the layers in currentLayers, - // and update their transform hint. - // - // If a layer is visible only on a single display, then that - // display is used to calculate the hint, otherwise we use the - // default display. + // Layers and/or displays have changed, so update the transform hint for each layer. // // NOTE: we do this here, rather than when presenting the display so that // the hint is set before we acquire a buffer from the surface texture. @@ -2962,30 +2951,29 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { // (soon to become the drawing state list). // sp hintDisplay; - uint32_t currentlayerStack = 0; - bool first = true; + ui::LayerStack layerStack; + mCurrentState.traverse([&](Layer* layer) REQUIRES(mStateLock) { // NOTE: we rely on the fact that layers are sorted by // layerStack first (so we don't have to traverse the list // of displays for every layer). - uint32_t layerStack = layer->getLayerStack(); - if (first || currentlayerStack != layerStack) { - currentlayerStack = layerStack; - // figure out if this layerstack is mirrored - // (more than one display) if so, pick the default display, - // if not, pick the only display it's on. + if (const auto filter = layer->getOutputFilter(); layerStack != filter.layerStack) { + layerStack = filter.layerStack; hintDisplay = nullptr; + + // Find the display that includes the layer. for (const auto& [token, display] : mDisplays) { - if (display->getCompositionDisplay() - ->belongsInOutput(layer->getLayerStack(), - layer->getPrimaryDisplayOnly())) { - if (hintDisplay) { - hintDisplay = nullptr; - break; - } else { - hintDisplay = display; - } + if (!display->getCompositionDisplay()->includesLayer(filter)) { + continue; } + + // Pick the primary display if another display mirrors the layer. + if (hintDisplay) { + hintDisplay = nullptr; + break; + } + + hintDisplay = display; } } @@ -2999,13 +2987,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { hintDisplay = getDefaultDisplayDeviceLocked(); } - // could be null if there is no display available at all to get - // the transform hint from. - if (hintDisplay) { - layer->updateTransformHint(hintDisplay->getTransformHint()); - } - - first = false; + layer->updateTransformHint(hintDisplay->getTransformHint()); }); } @@ -3069,9 +3051,12 @@ void SurfaceFlinger::notifyWindowInfos() { mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; - sp display = enablePerWindowInputRotation() - ? ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)) - : nullptr; + + const DisplayDevice* display = nullptr; + if (enablePerWindowInputRotation()) { + display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get(); + } + // When calculating the screen bounds we ignore the transparent region since it may // result in an unwanted offset. windowInfos.push_back(layer->fillInputInfo(display)); @@ -3243,7 +3228,7 @@ void SurfaceFlinger::commitOffscreenLayers() { void SurfaceFlinger::invalidateLayerStack(const sp& layer, const Region& dirty) { for (const auto& [token, displayDevice] : ON_MAIN_THREAD(mDisplays)) { auto display = displayDevice->getCompositionDisplay(); - if (display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) { + if (display->includesLayer(layer->getOutputFilter())) { display->editState().dirtyRegion.orSelf(dirty); } } @@ -4464,7 +4449,7 @@ void SurfaceFlinger::onInitializeDisplays() { d.what = DisplayState::eDisplayProjectionChanged | DisplayState::eLayerStackChanged; d.token = token; - d.layerStack = 0; + d.layerStack = ui::DEFAULT_LAYER_STACK; d.orientation = ui::ROTATION_0; d.orientedDisplaySpaceRect.makeInvalid(); d.layerStackSpaceRect.makeInvalid(); @@ -4495,23 +4480,22 @@ void SurfaceFlinger::initializeDisplays() { } sp SurfaceFlinger::getDisplayWithInputByLayer(Layer* layer) const { - sp display; - for (const auto& pair : mDisplays) { - const auto& displayDevice = pair.second; - if (!displayDevice->receivesInput() || - !displayDevice->getCompositionDisplay() - ->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) { + const auto filter = layer->getOutputFilter(); + sp inputDisplay; + + for (const auto& [_, display] : mDisplays) { + if (!display->receivesInput() || !display->getCompositionDisplay()->includesLayer(filter)) { continue; } // Don't return immediately so that we can log duplicates. - if (display) { - ALOGE("Multiple display devices claim to accept input for the same layerstack: %d", - layer->getLayerStack()); + if (inputDisplay) { + ALOGE("Multiple displays claim to accept input for the same layer stack: %u", + filter.layerStack.id); continue; } - display = displayDevice; + inputDisplay = display; } - return display; + return inputDisplay; } void SurfaceFlinger::setPowerModeInternal(const sp& display, hal::PowerMode mode) { @@ -6417,12 +6401,12 @@ void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack, const // We loop through the first level of layers without traversing, // as we need to determine which layers belong to the requested display. for (const auto& layer : mDrawingState.layersSortedByZ) { - if (!layer->belongsToDisplay(layerStack)) { + if (layer->getLayerStack() != layerStack) { continue; } // relative layers are traversed in Layer::traverseInZOrder layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - if (layer->getPrimaryDisplayOnly()) { + if (layer->isInternalDisplayOverlay()) { return; } if (!layer->isVisible()) { diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index 9be3abefab..0782fef8ea 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -323,11 +323,10 @@ void SurfaceInterceptor::addFlagsLocked(Transaction* transaction, int32_t layerI } void SurfaceInterceptor::addLayerStackLocked(Transaction* transaction, int32_t layerId, - uint32_t layerStack) -{ + ui::LayerStack layerStack) { SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); LayerStackChange* layerStackChange(change->mutable_layer_stack()); - layerStackChange->set_layer_stack(layerStack); + layerStackChange->set_layer_stack(layerStack.id); } void SurfaceInterceptor::addCropLocked(Transaction* transaction, int32_t layerId, @@ -568,12 +567,11 @@ void SurfaceInterceptor::addDisplaySurfaceLocked(Transaction* transaction, int32 } } -void SurfaceInterceptor::addDisplayLayerStackLocked(Transaction* transaction, - int32_t sequenceId, uint32_t layerStack) -{ +void SurfaceInterceptor::addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId, + ui::LayerStack layerStack) { DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId)); LayerStackChange* layerStackChange(dispChange->mutable_layer_stack()); - layerStackChange->set_layer_stack(layerStack); + layerStackChange->set_layer_stack(layerStack.id); } void SurfaceInterceptor::addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId, diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h index 7b331b9f5f..970c3e5c27 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -160,7 +160,7 @@ private: void addTransparentRegionLocked(Transaction* transaction, int32_t layerId, const Region& transRegion); void addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags, uint8_t mask); - void addLayerStackLocked(Transaction* transaction, int32_t layerId, uint32_t layerStack); + void addLayerStackLocked(Transaction* transaction, int32_t layerId, ui::LayerStack); void addCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect); void addCornerRadiusLocked(Transaction* transaction, int32_t layerId, float cornerRadius); void addBackgroundBlurRadiusLocked(Transaction* transaction, int32_t layerId, @@ -183,8 +183,7 @@ private: DisplayChange* createDisplayChangeLocked(Transaction* transaction, int32_t sequenceId); void addDisplaySurfaceLocked(Transaction* transaction, int32_t sequenceId, const sp& surface); - void addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId, - uint32_t layerStack); + void addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId, ui::LayerStack); void addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId, uint32_t flags); void addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId, uint32_t w, uint32_t h); diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index fa3f0e7239..d33bc1080c 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -93,7 +93,7 @@ protected: ASSERT_TRUE(mBGSurfaceControl->isValid()); Transaction t; - t.setDisplayLayerStack(mDisplay, 0); + t.setDisplayLayerStack(mDisplay, ui::DEFAULT_LAYER_STACK); ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX - 3).show(mBGSurfaceControl).apply()); } diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp index af00ec7fc9..1361ded67d 100644 --- a/services/surfaceflinger/tests/EffectLayer_test.cpp +++ b/services/surfaceflinger/tests/EffectLayer_test.cpp @@ -33,7 +33,7 @@ protected: mParentLayer = createColorLayer("Parent layer", Color::RED); asTransaction([&](Transaction& t) { - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer); t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque); }); diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp index 9fa3d4c417..8d7e175cec 100644 --- a/services/surfaceflinger/tests/IPC_test.cpp +++ b/services/surfaceflinger/tests/IPC_test.cpp @@ -159,7 +159,7 @@ public: {0, 0, static_cast(width), static_cast(height)}, Color::RED); - transaction->setLayerStack(mSurfaceControl, 0) + transaction->setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK) .setLayer(mSurfaceControl, std::numeric_limits::max()) .setBuffer(mSurfaceControl, gb) .setAcquireFence(mSurfaceControl, fence) @@ -232,7 +232,7 @@ public: mDisplayHeight = mode.resolution.getHeight(); Transaction setupTransaction; - setupTransaction.setDisplayLayerStack(mPrimaryDisplay, 0); + setupTransaction.setDisplayLayerStack(mPrimaryDisplay, ui::DEFAULT_LAYER_STACK); setupTransaction.apply(); } @@ -310,7 +310,7 @@ TEST_F(IPCTest, MergeBasic) { Color::RED); Transaction transaction; - transaction.setLayerStack(sc, 0) + transaction.setLayerStack(sc, ui::DEFAULT_LAYER_STACK) .setLayer(sc, std::numeric_limits::max() - 1) .setBuffer(sc, gb) .setAcquireFence(sc, fence) diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 0bc8fe7aa0..6bd7920a62 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -266,7 +266,7 @@ protected: sp mDisplay; uint32_t mDisplayWidth; uint32_t mDisplayHeight; - uint32_t mDisplayLayerStack; + ui::LayerStack mDisplayLayerStack = ui::DEFAULT_LAYER_STACK; Rect mDisplayRect = Rect::INVALID_RECT; // leave room for ~256 layers @@ -294,8 +294,6 @@ private: // vsyncs. mBufferPostDelay = static_cast(1e6 / mode.refreshRate) * 3; - mDisplayLayerStack = 0; - mBlackBgSurface = createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect); diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index 43d957cf7a..407625313c 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -643,7 +643,8 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetLayerStackBasic) { ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32)); - Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply(); + const auto layerStack = ui::LayerStack::fromValue(mDisplayLayerStack.id + 1); + Transaction().setLayerStack(layer, layerStack).apply(); { SCOPED_TRACE("non-existing layer stack"); getScreenCapture()->expectColor(mDisplayRect, Color::BLACK); diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index ee4d367f3d..e1a7ecc03b 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -63,7 +63,7 @@ protected: TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); asTransaction([&](Transaction& t) { - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl); diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp index d02786504e..3ec6da9ff4 100644 --- a/services/surfaceflinger/tests/MirrorLayer_test.cpp +++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp @@ -36,7 +36,7 @@ protected: mParentLayer = createColorLayer("Parent layer", Color::RED); mChildLayer = createColorLayer("Child layer", Color::GREEN, mParentLayer.get()); asTransaction([&](Transaction& t) { - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer); t.setCrop(mChildLayer, Rect(0, 0, 400, 400)).show(mChildLayer); t.setPosition(mChildLayer, 50, 50); diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp index 08de01cdfb..1ed6c65afb 100644 --- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp +++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp @@ -52,7 +52,7 @@ protected: mColorLayer = 0; } - void createDisplay(const ui::Size& layerStackSize, uint32_t layerStack) { + void createDisplay(const ui::Size& layerStackSize, ui::LayerStack layerStack) { mVirtualDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/); asTransaction([&](Transaction& t) { @@ -63,7 +63,7 @@ protected: }); } - void createColorLayer(uint32_t layerStack) { + void createColorLayer(ui::LayerStack layerStack) { mColorLayer = createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect); @@ -90,8 +90,9 @@ protected: }; TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) { - createDisplay(mMainDisplayState.layerStackSpaceRect, 1 /* layerStack */); - createColorLayer(1 /* layerStack */); + constexpr ui::LayerStack kLayerStack{1u}; + createDisplay(mMainDisplayState.layerStackSpaceRect, kLayerStack); + createColorLayer(kLayerStack); asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); }); @@ -113,8 +114,8 @@ TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) { // Assumption here is that the new mirrored display has the same layer stack rect as the // primary display that it is mirroring. - createDisplay(mMainDisplayState.layerStackSpaceRect, 0 /* layerStack */); - createColorLayer(0 /* layerStack */); + createDisplay(mMainDisplayState.layerStackSpaceRect, ui::DEFAULT_LAYER_STACK); + createColorLayer(ui::DEFAULT_LAYER_STACK); asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); }); diff --git a/services/surfaceflinger/tests/RelativeZ_test.cpp b/services/surfaceflinger/tests/RelativeZ_test.cpp index fde6e6eff8..50a4092ddb 100644 --- a/services/surfaceflinger/tests/RelativeZ_test.cpp +++ b/services/surfaceflinger/tests/RelativeZ_test.cpp @@ -43,7 +43,7 @@ protected: mForegroundLayer = createColorLayer("Foreground layer", Color::GREEN); asTransaction([&](Transaction& t) { - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); t.setLayer(mBackgroundLayer, INT32_MAX - 2).show(mBackgroundLayer); t.setLayer(mForegroundLayer, INT32_MAX - 1).show(mForegroundLayer); }); diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index ab2064efd0..95301b3a37 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -53,7 +53,7 @@ protected: TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); asTransaction([&](Transaction& t) { - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl); @@ -563,7 +563,7 @@ TEST_F(ScreenCaptureTest, CaptureSecureLayer) { Transaction() .show(redLayer) .show(secureLayer) - .setLayerStack(redLayer, 0) + .setLayerStack(redLayer, ui::DEFAULT_LAYER_STACK) .setLayer(redLayer, INT32_MAX) .apply(); @@ -655,7 +655,7 @@ TEST_F(ScreenCaptureTest, CaptureDisplayPrimaryDisplayOnly) { Transaction() .show(layer) .hide(mFGSurfaceControl) - .setLayerStack(layer, 0) + .setLayerStack(layer, ui::DEFAULT_LAYER_STACK) .setLayer(layer, INT32_MAX) .setColor(layer, {layerColor.r / 255, layerColor.g / 255, layerColor.b / 255}) .setCrop(layer, bounds) @@ -702,7 +702,7 @@ TEST_F(ScreenCaptureTest, CaptureDisplayChildPrimaryDisplayOnly) { .show(layer) .show(childLayer) .hide(mFGSurfaceControl) - .setLayerStack(layer, 0) + .setLayerStack(layer, ui::DEFAULT_LAYER_STACK) .setLayer(layer, INT32_MAX) .setColor(layer, {layerColor.r / 255, layerColor.g / 255, layerColor.b / 255}) .setColor(childLayer, {childColor.r / 255, childColor.g / 255, childColor.b / 255}) diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index a42405989f..ee16f40b6d 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -283,7 +283,7 @@ void SurfaceInterceptorTest::setupBackgroundSurface() { ASSERT_TRUE(mFGSurfaceControl->isValid()); Transaction t; - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX - 3) .show(mBGSurfaceControl) @@ -380,7 +380,7 @@ void SurfaceInterceptorTest::transparentRegionHintUpdate(Transaction& t) { } void SurfaceInterceptorTest::layerStackUpdate(Transaction& t) { - t.setLayerStack(mBGSurfaceControl, STACK_UPDATE); + t.setLayerStack(mBGSurfaceControl, ui::LayerStack::fromValue(STACK_UPDATE)); } void SurfaceInterceptorTest::hiddenFlagUpdate(Transaction& t) { diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h index 89f608645d..60cffb19df 100644 --- a/services/surfaceflinger/tests/TransactionTestHarnesses.h +++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h @@ -65,7 +65,7 @@ public: SurfaceComposerClient::Transaction t; t.setDisplaySurface(vDisplay, producer); - t.setDisplayLayerStack(vDisplay, 0); + t.setDisplayLayerStack(vDisplay, ui::DEFAULT_LAYER_STACK); t.setDisplayProjection(vDisplay, displayState.orientation, Rect(displayState.layerStackSpaceRect), Rect(resolution)); t.apply(); diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp index 89228d55e5..de116f29ca 100644 --- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp +++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp @@ -84,7 +84,7 @@ TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { ISurfaceComposerClient::eFXSurfaceBufferState); Transaction() - .setLayerStack(surfaceControl, 0) + .setLayerStack(surfaceControl, ui::DEFAULT_LAYER_STACK) .show(surfaceControl) .setLayer(surfaceControl, INT32_MAX - 1) .setInputWindowInfo(surfaceControl, windowInfo) @@ -112,7 +112,7 @@ TEST_F(WindowInfosListenerTest, WindowInfoChanged) { ISurfaceComposerClient::eFXSurfaceBufferState); Transaction() - .setLayerStack(surfaceControl, 0) + .setLayerStack(surfaceControl, ui::DEFAULT_LAYER_STACK) .show(surfaceControl) .setLayer(surfaceControl, INT32_MAX - 1) .setInputWindowInfo(surfaceControl, windowInfo) diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index a9e935df22..b3b4ec15cd 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -363,7 +363,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -426,7 +426,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -479,7 +479,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -534,7 +534,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -586,7 +586,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -651,7 +651,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -703,7 +703,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -750,7 +750,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -797,7 +797,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -1195,7 +1195,7 @@ protected: fillSurfaceRGBA8(mFGSurfaceControl, RED); Transaction t; - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); t.setLayer(mBGSurfaceControl, INT32_MAX - 2); t.show(mBGSurfaceControl); @@ -1342,7 +1342,7 @@ protected: ALOGD("TransactionTest::SetLayerStack"); { TransactionScope ts(*sFakeComposer); - ts.setLayerStack(mFGSurfaceControl, 1); + ts.setLayerStack(mFGSurfaceControl, ui::LayerStack{1}); } // Foreground layer should have disappeared. diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 98c18890cf..0253c4cbbf 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -82,7 +82,7 @@ constexpr int DEFAULT_DISPLAY_WIDTH = 1920; constexpr int DEFAULT_DISPLAY_HEIGHT = 1024; constexpr int DEFAULT_TEXTURE_ID = 6000; -constexpr int DEFAULT_LAYER_STACK = 7000; +constexpr ui::LayerStack LAYER_STACK{7000u}; constexpr int DEFAULT_DISPLAY_MAX_LUMINANCE = 500; @@ -287,10 +287,8 @@ struct BaseDisplayVariant { auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() .setId(DEFAULT_DISPLAY_ID) - .setConnectionType(ui::DisplayConnectionType::Internal) .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) .setIsSecure(Derived::IS_SECURE) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&test->mPowerAdvisor) .setName(std::string("Injected display for ") + test_info->test_case_name() + "." + test_info->name()) @@ -309,7 +307,7 @@ struct BaseDisplayVariant { .setPowerMode(Derived::INIT_POWER_MODE) .inject(); Mock::VerifyAndClear(test->mNativeWindow); - test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK); + test->mDisplay->setLayerStack(LAYER_STACK); } template @@ -834,7 +832,7 @@ struct BaseLayerVariant { template static void initLayerDrawingStateAndComputeBounds(CompositionTest* test, sp layer) { auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer); - layerDrawingState.layerStack = DEFAULT_LAYER_STACK; + layerDrawingState.layerStack = LAYER_STACK; layerDrawingState.width = 100; layerDrawingState.height = 100; layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1], diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 60b0f5334c..5a21e7be5b 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -139,20 +139,18 @@ sp DisplayTransactionTest::injectDefaultInternalDisplay( EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)); EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(AnyNumber()); - constexpr auto kConnectionType = ui::DisplayConnectionType::Internal; - constexpr bool kIsPrimary = true; - auto compositionDisplay = compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(), compositionengine::DisplayCreationArgsBuilder() .setId(DEFAULT_DISPLAY_ID) - .setConnectionType(kConnectionType) .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) .setPowerAdvisor(&mPowerAdvisor) .build()); - auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, kConnectionType, + constexpr bool kIsPrimary = true; + auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, + ui::DisplayConnectionType::Internal, DEFAULT_DISPLAY_HWC_DISPLAY_ID, kIsPrimary); injector.setNativeWindow(mNativeWindow); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index de058a4f68..0f1cc6765d 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -267,11 +267,6 @@ struct DisplayVariant { .setPixels({WIDTH, HEIGHT}) .setPowerAdvisor(&test->mPowerAdvisor); - const auto connectionType = CONNECTION_TYPE::value; - if (connectionType) { - ceDisplayArgs.setConnectionType(*connectionType); - } - auto compositionDisplay = compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), ceDisplayArgs.build()); @@ -279,7 +274,7 @@ struct DisplayVariant { auto injector = TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, - connectionType, + CONNECTION_TYPE::value, HWC_DISPLAY_ID_OPT::value, static_cast(PRIMARY)); @@ -388,7 +383,6 @@ struct HwcDisplayVariant { auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() .setId(DisplayVariant::DISPLAY_ID::get()) - .setConnectionType(PhysicalDisplay::CONNECTION_TYPE) .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT}) .setIsSecure(static_cast(DisplayVariant::SECURE)) .setPowerAdvisor(&test->mPowerAdvisor) diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp index 313ab032f9..ef53aed091 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp @@ -534,8 +534,8 @@ TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) { TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) { using Case = NonHwcVirtualDisplayCase; - constexpr uint32_t oldLayerStack = 0u; - constexpr uint32_t newLayerStack = 123u; + constexpr ui::LayerStack oldLayerStack = ui::DEFAULT_LAYER_STACK; + constexpr ui::LayerStack newLayerStack{123u}; // -------------------------------------------------------------------- // Preconditions diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp index ef8b1493ae..bafa910270 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp @@ -63,15 +63,11 @@ TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) { // The primary display should have a current state ASSERT_TRUE(hasCurrentDisplayState(primaryDisplay.token())); const auto& primaryDisplayState = getCurrentDisplayState(primaryDisplay.token()); - // The layer stack state should be set to zero - EXPECT_EQ(0u, primaryDisplayState.layerStack); - // The orientation state should be set to zero - EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation); - // The orientedDisplaySpaceRect state should be set to INVALID + // The primary display state should be reset + EXPECT_EQ(ui::DEFAULT_LAYER_STACK, primaryDisplayState.layerStack); + EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation); EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.orientedDisplaySpaceRect); - - // The layerStackSpaceRect state should be set to INVALID EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.layerStackSpaceRect); // The width and height should both be zero @@ -99,4 +95,4 @@ TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) { } } // namespace -} // namespace android \ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp index fc40818ad1..7d9e22b23e 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp @@ -25,6 +25,8 @@ namespace android { namespace { +constexpr ui::LayerStack LAYER_STACK{456u}; + class SetDisplayStateLockedTest : public DisplayTransactionTest {}; TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingWithUnknownDisplay) { @@ -38,7 +40,7 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingWithUnknownDis DisplayState state; state.what = DisplayState::eLayerStackChanged; state.token = displayToken; - state.layerStack = 456; + state.layerStack = LAYER_STACK; // -------------------------------------------------------------------- // Invocation @@ -167,13 +169,13 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfLayerStackDi display.inject(); // The display has a layer stack set - display.mutableCurrentDisplayState().layerStack = 456u; + display.mutableCurrentDisplayState().layerStack = LAYER_STACK; // The incoming request sets the same layer stack DisplayState state; state.what = DisplayState::eLayerStackChanged; state.token = display.token(); - state.layerStack = 456u; + state.layerStack = LAYER_STACK; // -------------------------------------------------------------------- // Invocation @@ -187,7 +189,7 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfLayerStackDi EXPECT_EQ(0u, flags); // The current display state is unchanged - EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack); + EXPECT_EQ(LAYER_STACK, display.getCurrentDisplayState().layerStack); } TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStackChanged) { @@ -201,13 +203,13 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStac display.inject(); // The display has a layer stack set - display.mutableCurrentDisplayState().layerStack = 654u; + display.mutableCurrentDisplayState().layerStack = ui::LayerStack{LAYER_STACK.id + 1}; // The incoming request sets a different layer stack DisplayState state; state.what = DisplayState::eLayerStackChanged; state.token = display.token(); - state.layerStack = 456u; + state.layerStack = LAYER_STACK; // -------------------------------------------------------------------- // Invocation @@ -221,7 +223,7 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStac EXPECT_EQ(eDisplayTransactionNeeded, flags); // The desired display state has been set to the new value. - EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack); + EXPECT_EQ(LAYER_STACK, display.getCurrentDisplayState().layerStack); } TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfFlagsNotChanged) { -- cgit v1.2.3-59-g8ed1b From abdf4dab40d023d4e0b8ebf93686829f6a41e746 Mon Sep 17 00:00:00 2001 From: Pablo Gamito Date: Tue, 10 Aug 2021 09:55:42 +0000 Subject: Add requested_corner_radius to layer proto Test: Check that it shows up in the dumped proto files (e.g. Winscope) Bug: 193875495 Change-Id: Ib9f68260f73aff3adc455b5ea8e314a96e514fa7 --- services/surfaceflinger/Layer.cpp | 1 + services/surfaceflinger/layerproto/layers.proto | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 28c8213fc9..cc7ff1630f 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2031,6 +2031,7 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, layerInfo->set_curr_frame(mCurrentFrameNumber); layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); + layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius); layerInfo->set_corner_radius(getRoundedCornerState().radius); layerInfo->set_background_blur_radius(getBackgroundBlurRadius()); layerInfo->set_is_trusted_overlay(isTrustedOverlay()); diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto index dddc677715..9f4e7d2eb2 100644 --- a/services/surfaceflinger/layerproto/layers.proto +++ b/services/surfaceflinger/layerproto/layers.proto @@ -130,6 +130,9 @@ message LayerProto { repeated BlurRegion blur_regions = 54; bool is_trusted_overlay = 55; + + // Corner radius explicitly set on layer rather than inherited + float requested_corner_radius = 56; } message PositionProto { @@ -228,4 +231,4 @@ message BlurRegion { int32 top = 8; int32 right = 9; int32 bottom = 10; -} \ No newline at end of file +} -- cgit v1.2.3-59-g8ed1b From 9e168db5ff17fe32d3686a166ad0bc7720db12a7 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 27 May 2021 16:05:12 -0700 Subject: SF: Clean up around transaction commit Rename the vague helpers for transaction commit, and getTransactionFlags so its mutable operation is apparent. Inline superfluous variables and a 3-line function. Bug: 182939859 Test: Build Change-Id: I29637d0f77e8d22ce0f6ba045e4ec80274f614e8 --- services/surfaceflinger/Layer.cpp | 12 +- services/surfaceflinger/Layer.h | 8 +- services/surfaceflinger/SurfaceFlinger.cpp | 105 ++- services/surfaceflinger/SurfaceFlinger.h | 29 +- services/surfaceflinger/tests/unittests/Android.bp | 4 +- ...SurfaceFlinger_DisplayTransactionCommitTest.cpp | 792 ++++++++++++++++++++ .../SurfaceFlinger_HandleTransactionLockedTest.cpp | 793 --------------------- .../tests/unittests/TestableSurfaceFlinger.h | 8 +- 8 files changed, 873 insertions(+), 878 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp delete mode 100644 services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d27b51b345..b6e21b8395 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -725,14 +725,14 @@ void Layer::commitTransaction(State&) { mDrawingState.bufferlessSurfaceFramesTX.clear(); } -uint32_t Layer::getTransactionFlags(uint32_t flags) { - auto ret = mTransactionFlags & flags; - mTransactionFlags &= ~flags; - return ret; +uint32_t Layer::clearTransactionFlags(uint32_t mask) { + const auto flags = mTransactionFlags & mask; + mTransactionFlags &= ~mask; + return flags; } -uint32_t Layer::setTransactionFlags(uint32_t flags) { - return mTransactionFlags |= flags; +void Layer::setTransactionFlags(uint32_t mask) { + mTransactionFlags |= mask; } bool Layer::setPosition(float x, float y) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 60a66f4707..4200be4898 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -640,8 +640,12 @@ public: bool isLegacyDataSpace() const; uint32_t getTransactionFlags() const { return mTransactionFlags; } - uint32_t getTransactionFlags(uint32_t flags); - uint32_t setTransactionFlags(uint32_t flags); + + // Sets the masked bits. + void setTransactionFlags(uint32_t mask); + + // Clears and returns the masked bits. + uint32_t clearTransactionFlags(uint32_t mask); FloatRect getBounds(const Region& activeTransparentRegion) const; FloatRect getBounds() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index bf53c5e004..5d8d79b11b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1962,7 +1962,7 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT mFrameTimeline->setSfWakeUp(vsyncId, frameStart, Fps::fromPeriodNsecs(stats.vsyncPeriod)); - refreshNeeded |= handleMessageTransaction(); + refreshNeeded |= flushAndCommitTransactions(); refreshNeeded |= handleMessageInvalidate(); if (tracePreComposition) { @@ -2007,25 +2007,23 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT notifyRegionSamplingThread(); } -bool SurfaceFlinger::handleMessageTransaction() { +bool SurfaceFlinger::flushAndCommitTransactions() { ATRACE_CALL(); - if (getTransactionFlags(eTransactionFlushNeeded)) { + if (clearTransactionFlags(eTransactionFlushNeeded)) { flushTransactionQueues(); } - uint32_t transactionFlags = peekTransactionFlags(); - bool runHandleTransaction = - ((transactionFlags & (~eTransactionFlushNeeded)) != 0) || mForceTraversal; - if (runHandleTransaction) { - handleTransaction(eTransactionMask); + const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || mForceTraversal; + if (shouldCommit) { + commitTransactions(); } if (transactionFlushNeeded()) { setTransactionFlags(eTransactionFlushNeeded); } - return runHandleTransaction; + return shouldCommit; } void SurfaceFlinger::onMessageRefresh() { @@ -2451,29 +2449,26 @@ void SurfaceFlinger::postFrame() { } } -void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { +void SurfaceFlinger::commitTransactions() { ATRACE_CALL(); - // here we keep a copy of the drawing state (that is the state that's - // going to be overwritten by handleTransactionLocked()) outside of - // mStateLock so that the side-effects of the State assignment - // don't happen with mStateLock held (which can cause deadlocks). + // Keep a copy of the drawing state (that is going to be overwritten + // by commitTransactionsLocked) outside of mStateLock so that the side + // effects of the State assignment don't happen with mStateLock held, + // which can cause deadlocks. State drawingState(mDrawingState); - Mutex::Autolock _l(mStateLock); + Mutex::Autolock lock(mStateLock); mDebugInTransaction = systemTime(); // Here we're guaranteed that some transaction flags are set - // so we can call handleTransactionLocked() unconditionally. - // We call getTransactionFlags(), which will also clear the flags, - // with mStateLock held to guarantee that mCurrentState won't change - // until the transaction is committed. + // so we can call commitTransactionsLocked unconditionally. + // We clear the flags with mStateLock held to guarantee that + // mCurrentState won't change until the transaction is committed. modulateVsync(&VsyncModulator::onTransactionCommit); - transactionFlags = getTransactionFlags(eTransactionMask); - handleTransactionLocked(transactionFlags); + commitTransactionsLocked(clearTransactionFlags(eTransactionMask)); mDebugInTransaction = 0; - // here the transaction has been committed } void SurfaceFlinger::loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& outModes, @@ -2927,8 +2922,8 @@ void SurfaceFlinger::processDisplayChangesLocked() { mDrawingState.displays = mCurrentState.displays; } -void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { - // Commit display transactions +void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { + // Commit display transactions. const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded; if (displayTransactionNeeded) { processDisplayChangesLocked(); @@ -2942,7 +2937,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { mSomeChildrenChanged = false; } - // Update transform hint + // Update transform hint. if (transactionFlags & (eTransformHintUpdateNeeded | eDisplayTransactionNeeded)) { // Layers and/or displays have changed, so update the transform hint for each layer. // @@ -2995,10 +2990,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { }); } - /* - * Perform our own transaction if needed - */ - if (mLayersAdded) { mLayersAdded = false; // Layers have been added. @@ -3020,7 +3011,9 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { }); } - commitTransaction(); + doCommitTransactions(); + signalSynchronousTransactions(CountDownLatch::eSyncTransaction); + mAnimTransactionPending = false; } void SurfaceFlinger::updateInputFlinger() { @@ -3169,14 +3162,9 @@ void SurfaceFlinger::setVsyncConfig(const VsyncModulator::VsyncConfig& config, mEventQueue->setDuration(config.sfWorkDuration); } -void SurfaceFlinger::commitTransaction() { +void SurfaceFlinger::doCommitTransactions() { ATRACE_CALL(); - commitTransactionLocked(); - signalSynchronousTransactions(CountDownLatch::eSyncTransaction); - mAnimTransactionPending = false; -} -void SurfaceFlinger::commitTransactionLocked() { if (!mLayersPendingRemoval.isEmpty()) { // Notify removed layers now that they can't be drawn from for (const auto& l : mLayersPendingRemoval) { @@ -3220,11 +3208,10 @@ void SurfaceFlinger::commitTransactionLocked() { void SurfaceFlinger::commitOffscreenLayers() { for (Layer* offscreenLayer : mOffscreenLayers) { offscreenLayer->traverse(LayerVector::StateSet::Drawing, [](Layer* layer) { - uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); - if (!trFlags) return; - - layer->doTransaction(0); - layer->commitChildList(); + if (layer->clearTransactionFlags(eTransactionNeeded)) { + layer->doTransaction(0); + layer->commitChildList(); + } }); } } @@ -3260,14 +3247,14 @@ bool SurfaceFlinger::handlePageFlip() { // Display is now waiting on Layer 1's frame, which is behind layer 0's // second frame. But layer 0's second frame could be waiting on display. mDrawingState.traverse([&](Layer* layer) { - uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); - if (trFlags || mForceTransactionDisplayChange) { - const uint32_t flags = layer->doTransaction(0); - if (flags & Layer::eVisibleRegion) - mVisibleRegionsDirty = true; - } + if (layer->clearTransactionFlags(eTransactionNeeded) || mForceTransactionDisplayChange) { + const uint32_t flags = layer->doTransaction(0); + if (flags & Layer::eVisibleRegion) { + mVisibleRegionsDirty = true; + } + } - if (layer->hasReadyFrame()) { + if (layer->hasReadyFrame()) { frameQueued = true; if (layer->shouldPresentNow(expectedPresentTime)) { mLayersWithQueuedFrames.emplace(layer); @@ -3275,7 +3262,7 @@ bool SurfaceFlinger::handlePageFlip() { ATRACE_NAME("!layer->shouldPresentNow()"); layer->useEmptyDamage(); } - } else { + } else { layer->useEmptyDamage(); } }); @@ -3374,23 +3361,23 @@ void SurfaceFlinger::removeGraphicBufferProducerAsync(const wp& binder) })); } -uint32_t SurfaceFlinger::peekTransactionFlags() { +uint32_t SurfaceFlinger::getTransactionFlags() const { return mTransactionFlags; } -uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) { - return mTransactionFlags.fetch_and(~flags) & flags; +uint32_t SurfaceFlinger::clearTransactionFlags(uint32_t mask) { + return mTransactionFlags.fetch_and(~mask) & mask; } -uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) { - return setTransactionFlags(flags, TransactionSchedule::Late); +uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask) { + return setTransactionFlags(mask, TransactionSchedule::Late); } -uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule, - const sp& token) { - uint32_t old = mTransactionFlags.fetch_or(flags); - modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, token); - if ((old & flags) == 0) scheduleInvalidate(FrameHint::kActive); +uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule, + const sp& applyToken) { + const uint32_t old = mTransactionFlags.fetch_or(mask); + modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, applyToken); + if ((old & mask) == 0) scheduleInvalidate(FrameHint::kActive); return old; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 00d42af1ed..33bc17ba73 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -352,7 +352,6 @@ protected: uint32_t permissions, std::unordered_set& listenerCallbacks) REQUIRES(mStateLock); - virtual void commitTransactionLocked(); // Used internally by computeLayerBounds() to gets the clip rectangle to use for the // root layers on a particular display in layer-coordinate space. The @@ -804,8 +803,12 @@ private: // incoming transactions void onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime); - // Returns whether the transaction actually modified any state - bool handleMessageTransaction(); + // Returns whether transactions were committed. + bool flushAndCommitTransactions() EXCLUDES(mStateLock); + + void commitTransactions() EXCLUDES(mStateLock); + void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock); + void doCommitTransactions() REQUIRES(mStateLock); // Handle the REFRESH message queue event, sending the current frame down to RenderEngine and // the Composer HAL for presentation @@ -814,9 +817,6 @@ private: // Returns whether a new buffer has been latched (see handlePageFlip()) bool handleMessageInvalidate(); - void handleTransaction(uint32_t transactionFlags); - void handleTransactionLocked(uint32_t transactionFlags) REQUIRES(mStateLock); - void updateInputFlinger(); void notifyWindowInfos(); void commitInputWindowCommands() REQUIRES(mStateLock); @@ -848,18 +848,23 @@ private: void flushTransactionQueues(); // Returns true if there is at least one transaction that needs to be flushed bool transactionFlushNeeded(); - uint32_t getTransactionFlags(uint32_t flags); - uint32_t peekTransactionFlags(); - // Can only be called from the main thread or with mStateLock held - uint32_t setTransactionFlags(uint32_t flags); + + uint32_t getTransactionFlags() const; + + // Sets the masked bits, and returns the old flags. + uint32_t setTransactionFlags(uint32_t mask); + + // Clears and returns the masked bits. + uint32_t clearTransactionFlags(uint32_t mask); + // Indicate SF should call doTraversal on layers, but don't trigger a wakeup! We use this cases // where there are still pending transactions but we know they won't be ready until a frame // arrives from a different layer. So we need to ensure we performTransaction from invalidate // but there is no need to try and wake up immediately to do it. Rather we rely on // onFrameAvailable or another layer update to wake us up. void setTraversalNeeded(); - uint32_t setTransactionFlags(uint32_t flags, TransactionSchedule, const sp& = {}); - void commitTransaction() REQUIRES(mStateLock); + uint32_t setTransactionFlags(uint32_t mask, TransactionSchedule, + const sp& applyToken = {}); void commitOffscreenLayers(); bool transactionIsReadyToBeApplied( const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 8bd6e62278..200ecbd894 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -70,10 +70,10 @@ cc_test { "MessageQueueTest.cpp", "SurfaceFlinger_CreateDisplayTest.cpp", "SurfaceFlinger_DestroyDisplayTest.cpp", + "SurfaceFlinger_DisplayTransactionCommitTest.cpp", "SurfaceFlinger_GetDisplayNativePrimariesTest.cpp", - "SurfaceFlinger_HandleTransactionLockedTest.cpp", - "SurfaceFlinger_NotifyPowerBoostTest.cpp", "SurfaceFlinger_HotplugTest.cpp", + "SurfaceFlinger_NotifyPowerBoostTest.cpp", "SurfaceFlinger_OnInitializeDisplaysTest.cpp", "SurfaceFlinger_SetDisplayStateTest.cpp", "SurfaceFlinger_SetPowerModeInternalTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp new file mode 100644 index 0000000000..6959ee35c3 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp @@ -0,0 +1,792 @@ +/* + * 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. + */ + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include "DisplayTransactionTestHelpers.h" + +namespace android { +namespace { + +struct DisplayTransactionCommitTest : DisplayTransactionTest { + template + void setupCommonPreconditions(); + + template + static void expectHotplugReceived(mock::EventThread*); + + template + void setupCommonCallExpectationsForConnectProcessing(); + + template + void setupCommonCallExpectationsForDisconnectProcessing(); + + template + void processesHotplugConnectCommon(); + + template + void ignoresHotplugConnectCommon(); + + template + void processesHotplugDisconnectCommon(); + + template + void verifyDisplayIsConnected(const sp& displayToken); + + template + void verifyPhysicalDisplayIsConnected(); + + void verifyDisplayIsNotConnected(const sp& displayToken); +}; + +template +void DisplayTransactionCommitTest::setupCommonPreconditions() { + // Wide color displays support is configured appropriately + Case::WideColorSupport::injectConfigChange(this); + + // SurfaceFlinger will use a test-controlled factory for BufferQueues + injectFakeBufferQueueFactory(); + + // SurfaceFlinger will use a test-controlled factory for native window + // surfaces. + injectFakeNativeWindowSurfaceFactory(); +} + +template +void DisplayTransactionCommitTest::expectHotplugReceived(mock::EventThread* eventThread) { + const auto convert = [](auto physicalDisplayId) { + return std::make_optional(DisplayId{physicalDisplayId}); + }; + + EXPECT_CALL(*eventThread, + onHotplugReceived(ResultOf(convert, Case::Display::DISPLAY_ID::get()), connected)) + .Times(1); +} + +template +void DisplayTransactionCommitTest::setupCommonCallExpectationsForConnectProcessing() { + Case::Display::setupHwcHotplugCallExpectations(this); + + Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this); + Case::Display::setupFramebufferProducerBufferQueueCallExpectations(this); + Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this); + Case::Display::setupHwcGetActiveConfigCallExpectations(this); + + Case::WideColorSupport::setupComposerCallExpectations(this); + Case::HdrSupport::setupComposerCallExpectations(this); + Case::PerFrameMetadataSupport::setupComposerCallExpectations(this); + + EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1); + expectHotplugReceived(mEventThread); + expectHotplugReceived(mSFEventThread); +} + +template +void DisplayTransactionCommitTest::setupCommonCallExpectationsForDisconnectProcessing() { + EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1); + + expectHotplugReceived(mEventThread); + expectHotplugReceived(mSFEventThread); +} + +template +void DisplayTransactionCommitTest::verifyDisplayIsConnected(const sp& displayToken) { + // The display device should have been set up in the list of displays. + ASSERT_TRUE(hasDisplayDevice(displayToken)); + const auto& device = getDisplayDevice(displayToken); + EXPECT_EQ(static_cast(Case::Display::SECURE), device->isSecure()); + EXPECT_EQ(static_cast(Case::Display::PRIMARY), device->isPrimary()); + + std::optional expectedPhysical; + if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) { + 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 = *displayId, + .type = *connectionType, + .hwcDisplayId = *hwcDisplayId}; + } + + // The display should have been set up in the current display state + ASSERT_TRUE(hasCurrentDisplayState(displayToken)); + const auto& current = getCurrentDisplayState(displayToken); + EXPECT_EQ(static_cast(Case::Display::VIRTUAL), current.isVirtual()); + EXPECT_EQ(expectedPhysical, current.physical); + + // The display should have been set up in the drawing display state + ASSERT_TRUE(hasDrawingDisplayState(displayToken)); + const auto& draw = getDrawingDisplayState(displayToken); + EXPECT_EQ(static_cast(Case::Display::VIRTUAL), draw.isVirtual()); + EXPECT_EQ(expectedPhysical, draw.physical); +} + +template +void DisplayTransactionCommitTest::verifyPhysicalDisplayIsConnected() { + // HWComposer should have an entry for the display + EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); + + // SF should have a display token. + const auto displayId = Case::Display::DISPLAY_ID::get(); + ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); + ASSERT_EQ(mFlinger.mutablePhysicalDisplayTokens().count(displayId), 1); + auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[displayId]; + + verifyDisplayIsConnected(displayToken); +} + +void DisplayTransactionCommitTest::verifyDisplayIsNotConnected(const sp& displayToken) { + EXPECT_FALSE(hasDisplayDevice(displayToken)); + EXPECT_FALSE(hasCurrentDisplayState(displayToken)); + EXPECT_FALSE(hasDrawingDisplayState(displayToken)); +} + +template +void DisplayTransactionCommitTest::processesHotplugConnectCommon() { + // -------------------------------------------------------------------- + // Preconditions + + setupCommonPreconditions(); + + // A hotplug connect event is enqueued for a display + Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED); + + // -------------------------------------------------------------------- + // Call Expectations + + setupCommonCallExpectationsForConnectProcessing(); + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + + // -------------------------------------------------------------------- + // Postconditions + + verifyPhysicalDisplayIsConnected(); + + // -------------------------------------------------------------------- + // Cleanup conditions + + EXPECT_CALL(*mComposer, + setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); + EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR)); +} + +template +void DisplayTransactionCommitTest::ignoresHotplugConnectCommon() { + // -------------------------------------------------------------------- + // Preconditions + + setupCommonPreconditions(); + + // A hotplug connect event is enqueued for a display + Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED); + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + + // -------------------------------------------------------------------- + // Postconditions + + // HWComposer should not have an entry for the display + EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); +} + +template +void DisplayTransactionCommitTest::processesHotplugDisconnectCommon() { + // -------------------------------------------------------------------- + // Preconditions + + setupCommonPreconditions(); + + // A hotplug disconnect event is enqueued for a display + Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED); + + // The display is already completely set up. + Case::Display::injectHwcDisplay(this); + auto existing = Case::Display::makeFakeExistingDisplayInjector(this); + existing.inject(); + + // -------------------------------------------------------------------- + // Call Expectations + + EXPECT_CALL(*mComposer, getDisplayIdentificationData(Case::Display::HWC_DISPLAY_ID, _, _)) + .Times(0); + + setupCommonCallExpectationsForDisconnectProcessing(); + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + + // -------------------------------------------------------------------- + // Postconditions + + // HWComposer should not have an entry for the display + EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); + + // SF should not have a display token. + const auto displayId = Case::Display::DISPLAY_ID::get(); + ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); + ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0); + + // The existing token should have been removed + verifyDisplayIsNotConnected(existing.token()); +} + +TEST_F(DisplayTransactionCommitTest, processesHotplugConnectPrimaryDisplay) { + processesHotplugConnectCommon(); +} + +TEST_F(DisplayTransactionCommitTest, processesHotplugConnectExternalDisplay) { + // Inject a primary display. + PrimaryDisplayVariant::injectHwcDisplay(this); + + processesHotplugConnectCommon(); +} + +TEST_F(DisplayTransactionCommitTest, ignoresHotplugConnectIfPrimaryAndExternalAlreadyConnected) { + // Inject both a primary and external display. + PrimaryDisplayVariant::injectHwcDisplay(this); + ExternalDisplayVariant::injectHwcDisplay(this); + + // TODO: This is an unnecessary call. + EXPECT_CALL(*mComposer, + getDisplayIdentificationData(TertiaryDisplayVariant::HWC_DISPLAY_ID, _, _)) + .WillOnce(DoAll(SetArgPointee<1>(TertiaryDisplay::PORT), + SetArgPointee<2>(TertiaryDisplay::GET_IDENTIFICATION_DATA()), + Return(Error::NONE))); + + ignoresHotplugConnectCommon(); +} + +TEST_F(DisplayTransactionCommitTest, processesHotplugDisconnectPrimaryDisplay) { + EXPECT_EXIT(processesHotplugDisconnectCommon(), + testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected."); +} + +TEST_F(DisplayTransactionCommitTest, processesHotplugDisconnectExternalDisplay) { + processesHotplugDisconnectCommon(); +} + +TEST_F(DisplayTransactionCommitTest, processesHotplugConnectThenDisconnectPrimary) { + EXPECT_EXIT( + [this] { + using Case = SimplePrimaryDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + setupCommonPreconditions(); + + // A hotplug connect event is enqueued for a display + Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED); + // A hotplug disconnect event is also enqueued for the same display + Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED); + + // -------------------------------------------------------------------- + // Call Expectations + + setupCommonCallExpectationsForConnectProcessing(); + setupCommonCallExpectationsForDisconnectProcessing(); + + EXPECT_CALL(*mComposer, + setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, + IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); + EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR)); + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + + // -------------------------------------------------------------------- + // Postconditions + + // HWComposer should not have an entry for the display + EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); + + // SF should not have a display token. + const auto displayId = Case::Display::DISPLAY_ID::get(); + ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); + ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0); + }(), + testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected."); +} + +TEST_F(DisplayTransactionCommitTest, processesHotplugDisconnectThenConnectPrimary) { + EXPECT_EXIT( + [this] { + using Case = SimplePrimaryDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + setupCommonPreconditions(); + + // The display is already completely set up. + Case::Display::injectHwcDisplay(this); + auto existing = Case::Display::makeFakeExistingDisplayInjector(this); + existing.inject(); + + // A hotplug disconnect event is enqueued for a display + Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED); + // A hotplug connect event is also enqueued for the same display + Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED); + + // -------------------------------------------------------------------- + // Call Expectations + + setupCommonCallExpectationsForConnectProcessing(); + setupCommonCallExpectationsForDisconnectProcessing(); + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + + // -------------------------------------------------------------------- + // Postconditions + + // The existing token should have been removed + verifyDisplayIsNotConnected(existing.token()); + const auto displayId = Case::Display::DISPLAY_ID::get(); + 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 + + verifyPhysicalDisplayIsConnected(); + + // -------------------------------------------------------------------- + // Cleanup conditions + + EXPECT_CALL(*mComposer, + setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, + IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); + EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR)); + }(), + testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected."); +} + +TEST_F(DisplayTransactionCommitTest, processesVirtualDisplayAdded) { + using Case = HwcVirtualDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + // The HWC supports at least one virtual display + injectMockComposer(1); + + setupCommonPreconditions(); + + // A virtual display was added to the current state, and it has a + // surface(producer) + sp displayToken = new BBinder(); + + DisplayDeviceState state; + state.isSecure = static_cast(Case::Display::SECURE); + + sp surface{new mock::GraphicBufferProducer()}; + state.surface = surface; + mFlinger.mutableCurrentState().displays.add(displayToken, state); + + // -------------------------------------------------------------------- + // Call Expectations + + Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this); + Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this); + + EXPECT_CALL(*surface, query(NATIVE_WINDOW_WIDTH, _)) + .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::WIDTH), Return(NO_ERROR))); + EXPECT_CALL(*surface, query(NATIVE_WINDOW_HEIGHT, _)) + .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::HEIGHT), Return(NO_ERROR))); + EXPECT_CALL(*surface, query(NATIVE_WINDOW_FORMAT, _)) + .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT), + Return(NO_ERROR))); + EXPECT_CALL(*surface, query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, _)) + .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR))); + + EXPECT_CALL(*surface, setAsyncMode(true)).Times(1); + + EXPECT_CALL(*mProducer, connect(_, NATIVE_WINDOW_API_EGL, false, _)).Times(1); + EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1); + + Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this); + Case::WideColorSupport::setupComposerCallExpectations(this); + Case::HdrSupport::setupComposerCallExpectations(this); + Case::PerFrameMetadataSupport::setupComposerCallExpectations(this); + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + + // -------------------------------------------------------------------- + // Postconditions + + // The display device should have been set up in the list of displays. + verifyDisplayIsConnected(displayToken); + + // -------------------------------------------------------------------- + // Cleanup conditions + + EXPECT_CALL(*mComposer, destroyVirtualDisplay(Case::Display::HWC_DISPLAY_ID)) + .WillOnce(Return(Error::NONE)); + EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR)); + + // Cleanup + mFlinger.mutableCurrentState().displays.removeItem(displayToken); + mFlinger.mutableDrawingState().displays.removeItem(displayToken); +} + +TEST_F(DisplayTransactionCommitTest, processesVirtualDisplayAddedWithNoSurface) { + using Case = HwcVirtualDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + // The HWC supports at least one virtual display + injectMockComposer(1); + + setupCommonPreconditions(); + + // A virtual display was added to the current state, but it does not have a + // surface. + sp displayToken = new BBinder(); + + DisplayDeviceState state; + state.isSecure = static_cast(Case::Display::SECURE); + + mFlinger.mutableCurrentState().displays.add(displayToken, state); + + // -------------------------------------------------------------------- + // Call Expectations + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + + // -------------------------------------------------------------------- + // Postconditions + + // There will not be a display device set up. + EXPECT_FALSE(hasDisplayDevice(displayToken)); + + // The drawing display state will be set from the current display state. + ASSERT_TRUE(hasDrawingDisplayState(displayToken)); + const auto& draw = getDrawingDisplayState(displayToken); + EXPECT_EQ(static_cast(Case::Display::VIRTUAL), draw.isVirtual()); +} + +TEST_F(DisplayTransactionCommitTest, processesVirtualDisplayRemoval) { + using Case = HwcVirtualDisplayCase; + + // -------------------------------------------------------------------- + // Preconditions + + // A virtual display is set up but is removed from the current state. + const auto displayId = Case::Display::DISPLAY_ID::get(); + ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId)); + mFlinger.mutableHwcDisplayData().try_emplace(displayId); + Case::Display::injectHwcDisplay(this); + auto existing = Case::Display::makeFakeExistingDisplayInjector(this); + existing.inject(); + mFlinger.mutableCurrentState().displays.removeItem(existing.token()); + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + + // -------------------------------------------------------------------- + // Postconditions + + // The existing token should have been removed + verifyDisplayIsNotConnected(existing.token()); +} + +TEST_F(DisplayTransactionCommitTest, processesDisplayLayerStackChanges) { + using Case = NonHwcVirtualDisplayCase; + + constexpr ui::LayerStack oldLayerStack = ui::DEFAULT_LAYER_STACK; + constexpr ui::LayerStack newLayerStack{123u}; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // There is a change to the layerStack state + display.mutableDrawingDisplayState().layerStack = oldLayerStack; + display.mutableCurrentDisplayState().layerStack = newLayerStack; + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + + // -------------------------------------------------------------------- + // Postconditions + + EXPECT_EQ(newLayerStack, display.mutableDisplayDevice()->getLayerStack()); +} + +TEST_F(DisplayTransactionCommitTest, processesDisplayTransformChanges) { + using Case = NonHwcVirtualDisplayCase; + + constexpr ui::Rotation oldTransform = ui::ROTATION_0; + constexpr ui::Rotation newTransform = ui::ROTATION_180; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // There is a change to the orientation state + display.mutableDrawingDisplayState().orientation = oldTransform; + display.mutableCurrentDisplayState().orientation = newTransform; + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + + // -------------------------------------------------------------------- + // Postconditions + + EXPECT_EQ(newTransform, display.mutableDisplayDevice()->getOrientation()); +} + +TEST_F(DisplayTransactionCommitTest, processesDisplayLayerStackRectChanges) { + using Case = NonHwcVirtualDisplayCase; + + const Rect oldLayerStackRect(0, 0, 0, 0); + const Rect newLayerStackRect(0, 0, 123, 456); + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // There is a change to the layerStackSpaceRect state + display.mutableDrawingDisplayState().layerStackSpaceRect = oldLayerStackRect; + display.mutableCurrentDisplayState().layerStackSpaceRect = newLayerStackRect; + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + + // -------------------------------------------------------------------- + // Postconditions + + EXPECT_EQ(newLayerStackRect, display.mutableDisplayDevice()->getLayerStackSpaceRect()); +} + +TEST_F(DisplayTransactionCommitTest, processesDisplayRectChanges) { + using Case = NonHwcVirtualDisplayCase; + + const Rect oldDisplayRect(0, 0); + const Rect newDisplayRect(123, 456); + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.inject(); + + // There is a change to the layerStackSpaceRect state + display.mutableDrawingDisplayState().orientedDisplaySpaceRect = oldDisplayRect; + display.mutableCurrentDisplayState().orientedDisplaySpaceRect = newDisplayRect; + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + + // -------------------------------------------------------------------- + // Postconditions + + EXPECT_EQ(newDisplayRect, display.mutableDisplayDevice()->getOrientedDisplaySpaceRect()); +} + +TEST_F(DisplayTransactionCommitTest, processesDisplayWidthChanges) { + using Case = NonHwcVirtualDisplayCase; + + constexpr int oldWidth = 0; + constexpr int oldHeight = 10; + constexpr int newWidth = 123; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto nativeWindow = new mock::NativeWindow(); + auto displaySurface = new compositionengine::mock::DisplaySurface(); + sp buf = new GraphicBuffer(); + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.setNativeWindow(nativeWindow); + display.setDisplaySurface(displaySurface); + // Setup injection expectations + EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _)) + .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0))); + EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) + .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0))); + EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1); + EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1); + EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1); + EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1); + display.inject(); + + // There is a change to the layerStackSpaceRect state + display.mutableDrawingDisplayState().width = oldWidth; + display.mutableDrawingDisplayState().height = oldHeight; + display.mutableCurrentDisplayState().width = newWidth; + display.mutableCurrentDisplayState().height = oldHeight; + + // -------------------------------------------------------------------- + // Call Expectations + + EXPECT_CALL(*displaySurface, resizeBuffers(ui::Size(newWidth, oldHeight))).Times(1); + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); +} + +TEST_F(DisplayTransactionCommitTest, processesDisplayHeightChanges) { + using Case = NonHwcVirtualDisplayCase; + + constexpr int oldWidth = 0; + constexpr int oldHeight = 10; + constexpr int newHeight = 123; + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto nativeWindow = new mock::NativeWindow(); + auto displaySurface = new compositionengine::mock::DisplaySurface(); + sp buf = new GraphicBuffer(); + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.setNativeWindow(nativeWindow); + display.setDisplaySurface(displaySurface); + // Setup injection expectations + EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _)) + .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0))); + EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) + .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0))); + EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1); + EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1); + EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1); + EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1); + display.inject(); + + // There is a change to the layerStackSpaceRect state + display.mutableDrawingDisplayState().width = oldWidth; + display.mutableDrawingDisplayState().height = oldHeight; + display.mutableCurrentDisplayState().width = oldWidth; + display.mutableCurrentDisplayState().height = newHeight; + + // -------------------------------------------------------------------- + // Call Expectations + + EXPECT_CALL(*displaySurface, resizeBuffers(ui::Size(oldWidth, newHeight))).Times(1); + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); +} + +TEST_F(DisplayTransactionCommitTest, processesDisplaySizeDisplayRectAndLayerStackRectChanges) { + using Case = NonHwcVirtualDisplayCase; + + constexpr uint32_t kOldWidth = 567; + constexpr uint32_t kOldHeight = 456; + const auto kOldSize = Rect(kOldWidth, kOldHeight); + + constexpr uint32_t kNewWidth = 234; + constexpr uint32_t kNewHeight = 123; + const auto kNewSize = Rect(kNewWidth, kNewHeight); + + // -------------------------------------------------------------------- + // Preconditions + + // A display is set up + auto nativeWindow = new mock::NativeWindow(); + auto displaySurface = new compositionengine::mock::DisplaySurface(); + sp buf = new GraphicBuffer(); + auto display = Case::Display::makeFakeExistingDisplayInjector(this); + display.setNativeWindow(nativeWindow); + display.setDisplaySurface(displaySurface); + // Setup injection expectations + EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _)) + .WillOnce(DoAll(SetArgPointee<1>(kOldWidth), Return(0))); + EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) + .WillOnce(DoAll(SetArgPointee<1>(kOldHeight), Return(0))); + display.inject(); + + // There is a change to the layerStackSpaceRect state + display.mutableDrawingDisplayState().width = kOldWidth; + display.mutableDrawingDisplayState().height = kOldHeight; + display.mutableDrawingDisplayState().layerStackSpaceRect = kOldSize; + display.mutableDrawingDisplayState().orientedDisplaySpaceRect = kOldSize; + + display.mutableCurrentDisplayState().width = kNewWidth; + display.mutableCurrentDisplayState().height = kNewHeight; + display.mutableCurrentDisplayState().layerStackSpaceRect = kNewSize; + display.mutableCurrentDisplayState().orientedDisplaySpaceRect = kNewSize; + + // -------------------------------------------------------------------- + // Call Expectations + + EXPECT_CALL(*displaySurface, resizeBuffers(kNewSize.getSize())).Times(1); + + // -------------------------------------------------------------------- + // Invocation + + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); + + EXPECT_EQ(display.mutableDisplayDevice()->getBounds(), kNewSize); + EXPECT_EQ(display.mutableDisplayDevice()->getWidth(), kNewWidth); + EXPECT_EQ(display.mutableDisplayDevice()->getHeight(), kNewHeight); + EXPECT_EQ(display.mutableDisplayDevice()->getOrientedDisplaySpaceRect(), kNewSize); + EXPECT_EQ(display.mutableDisplayDevice()->getLayerStackSpaceRect(), kNewSize); +} + +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp deleted file mode 100644 index ef53aed091..0000000000 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp +++ /dev/null @@ -1,793 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#undef LOG_TAG -#define LOG_TAG "LibSurfaceFlingerUnittests" - -#include "DisplayTransactionTestHelpers.h" - -namespace android { -namespace { - -class HandleTransactionLockedTest : public DisplayTransactionTest { -public: - template - void setupCommonPreconditions(); - - template - static void expectHotplugReceived(mock::EventThread*); - - template - void setupCommonCallExpectationsForConnectProcessing(); - - template - void setupCommonCallExpectationsForDisconnectProcessing(); - - template - void processesHotplugConnectCommon(); - - template - void ignoresHotplugConnectCommon(); - - template - void processesHotplugDisconnectCommon(); - - template - void verifyDisplayIsConnected(const sp& displayToken); - - template - void verifyPhysicalDisplayIsConnected(); - - void verifyDisplayIsNotConnected(const sp& displayToken); -}; - -template -void HandleTransactionLockedTest::setupCommonPreconditions() { - // Wide color displays support is configured appropriately - Case::WideColorSupport::injectConfigChange(this); - - // SurfaceFlinger will use a test-controlled factory for BufferQueues - injectFakeBufferQueueFactory(); - - // SurfaceFlinger will use a test-controlled factory for native window - // surfaces. - injectFakeNativeWindowSurfaceFactory(); -} - -template -void HandleTransactionLockedTest::expectHotplugReceived(mock::EventThread* eventThread) { - const auto convert = [](auto physicalDisplayId) { - return std::make_optional(DisplayId{physicalDisplayId}); - }; - - EXPECT_CALL(*eventThread, - onHotplugReceived(ResultOf(convert, Case::Display::DISPLAY_ID::get()), connected)) - .Times(1); -} - -template -void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() { - Case::Display::setupHwcHotplugCallExpectations(this); - - Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this); - Case::Display::setupFramebufferProducerBufferQueueCallExpectations(this); - Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this); - Case::Display::setupHwcGetActiveConfigCallExpectations(this); - - Case::WideColorSupport::setupComposerCallExpectations(this); - Case::HdrSupport::setupComposerCallExpectations(this); - Case::PerFrameMetadataSupport::setupComposerCallExpectations(this); - - EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1); - expectHotplugReceived(mEventThread); - expectHotplugReceived(mSFEventThread); -} - -template -void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() { - EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1); - - expectHotplugReceived(mEventThread); - expectHotplugReceived(mSFEventThread); -} - -template -void HandleTransactionLockedTest::verifyDisplayIsConnected(const sp& displayToken) { - // The display device should have been set up in the list of displays. - ASSERT_TRUE(hasDisplayDevice(displayToken)); - const auto& device = getDisplayDevice(displayToken); - EXPECT_EQ(static_cast(Case::Display::SECURE), device->isSecure()); - EXPECT_EQ(static_cast(Case::Display::PRIMARY), device->isPrimary()); - - std::optional expectedPhysical; - if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) { - 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 = *displayId, - .type = *connectionType, - .hwcDisplayId = *hwcDisplayId}; - } - - // The display should have been set up in the current display state - ASSERT_TRUE(hasCurrentDisplayState(displayToken)); - const auto& current = getCurrentDisplayState(displayToken); - EXPECT_EQ(static_cast(Case::Display::VIRTUAL), current.isVirtual()); - EXPECT_EQ(expectedPhysical, current.physical); - - // The display should have been set up in the drawing display state - ASSERT_TRUE(hasDrawingDisplayState(displayToken)); - const auto& draw = getDrawingDisplayState(displayToken); - EXPECT_EQ(static_cast(Case::Display::VIRTUAL), draw.isVirtual()); - EXPECT_EQ(expectedPhysical, draw.physical); -} - -template -void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() { - // HWComposer should have an entry for the display - EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); - - // SF should have a display token. - const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); - ASSERT_EQ(mFlinger.mutablePhysicalDisplayTokens().count(displayId), 1); - auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[displayId]; - - verifyDisplayIsConnected(displayToken); -} - -void HandleTransactionLockedTest::verifyDisplayIsNotConnected(const sp& displayToken) { - EXPECT_FALSE(hasDisplayDevice(displayToken)); - EXPECT_FALSE(hasCurrentDisplayState(displayToken)); - EXPECT_FALSE(hasDrawingDisplayState(displayToken)); -} - -template -void HandleTransactionLockedTest::processesHotplugConnectCommon() { - // -------------------------------------------------------------------- - // Preconditions - - setupCommonPreconditions(); - - // A hotplug connect event is enqueued for a display - Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED); - - // -------------------------------------------------------------------- - // Call Expectations - - setupCommonCallExpectationsForConnectProcessing(); - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); - - // -------------------------------------------------------------------- - // Postconditions - - verifyPhysicalDisplayIsConnected(); - - // -------------------------------------------------------------------- - // Cleanup conditions - - EXPECT_CALL(*mComposer, - setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE)) - .WillOnce(Return(Error::NONE)); - EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR)); -} - -template -void HandleTransactionLockedTest::ignoresHotplugConnectCommon() { - // -------------------------------------------------------------------- - // Preconditions - - setupCommonPreconditions(); - - // A hotplug connect event is enqueued for a display - Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED); - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); - - // -------------------------------------------------------------------- - // Postconditions - - // HWComposer should not have an entry for the display - EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); -} - -template -void HandleTransactionLockedTest::processesHotplugDisconnectCommon() { - // -------------------------------------------------------------------- - // Preconditions - - setupCommonPreconditions(); - - // A hotplug disconnect event is enqueued for a display - Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED); - - // The display is already completely set up. - Case::Display::injectHwcDisplay(this); - auto existing = Case::Display::makeFakeExistingDisplayInjector(this); - existing.inject(); - - // -------------------------------------------------------------------- - // Call Expectations - - EXPECT_CALL(*mComposer, getDisplayIdentificationData(Case::Display::HWC_DISPLAY_ID, _, _)) - .Times(0); - - setupCommonCallExpectationsForDisconnectProcessing(); - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); - - // -------------------------------------------------------------------- - // Postconditions - - // HWComposer should not have an entry for the display - EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); - - // SF should not have a display token. - const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); - ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0); - - // The existing token should have been removed - verifyDisplayIsNotConnected(existing.token()); -} - -TEST_F(HandleTransactionLockedTest, processesHotplugConnectPrimaryDisplay) { - processesHotplugConnectCommon(); -} - -TEST_F(HandleTransactionLockedTest, processesHotplugConnectExternalDisplay) { - // Inject a primary display. - PrimaryDisplayVariant::injectHwcDisplay(this); - - processesHotplugConnectCommon(); -} - -TEST_F(HandleTransactionLockedTest, ignoresHotplugConnectIfPrimaryAndExternalAlreadyConnected) { - // Inject both a primary and external display. - PrimaryDisplayVariant::injectHwcDisplay(this); - ExternalDisplayVariant::injectHwcDisplay(this); - - // TODO: This is an unnecessary call. - EXPECT_CALL(*mComposer, - getDisplayIdentificationData(TertiaryDisplayVariant::HWC_DISPLAY_ID, _, _)) - .WillOnce(DoAll(SetArgPointee<1>(TertiaryDisplay::PORT), - SetArgPointee<2>(TertiaryDisplay::GET_IDENTIFICATION_DATA()), - Return(Error::NONE))); - - ignoresHotplugConnectCommon(); -} - -TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectPrimaryDisplay) { - EXPECT_EXIT(processesHotplugDisconnectCommon(), - testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected."); -} - -TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectExternalDisplay) { - processesHotplugDisconnectCommon(); -} - -TEST_F(HandleTransactionLockedTest, processesHotplugConnectThenDisconnectPrimary) { - EXPECT_EXIT( - [this] { - using Case = SimplePrimaryDisplayCase; - - // -------------------------------------------------------------------- - // Preconditions - - setupCommonPreconditions(); - - // A hotplug connect event is enqueued for a display - Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED); - // A hotplug disconnect event is also enqueued for the same display - Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED); - - // -------------------------------------------------------------------- - // Call Expectations - - setupCommonCallExpectationsForConnectProcessing(); - setupCommonCallExpectationsForDisconnectProcessing(); - - EXPECT_CALL(*mComposer, - setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, - IComposerClient::Vsync::DISABLE)) - .WillOnce(Return(Error::NONE)); - EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR)); - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); - - // -------------------------------------------------------------------- - // Postconditions - - // HWComposer should not have an entry for the display - EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); - - // SF should not have a display token. - const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); - ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0); - }(), - testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected."); -} - -TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) { - EXPECT_EXIT( - [this] { - using Case = SimplePrimaryDisplayCase; - - // -------------------------------------------------------------------- - // Preconditions - - setupCommonPreconditions(); - - // The display is already completely set up. - Case::Display::injectHwcDisplay(this); - auto existing = Case::Display::makeFakeExistingDisplayInjector(this); - existing.inject(); - - // A hotplug disconnect event is enqueued for a display - Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED); - // A hotplug connect event is also enqueued for the same display - Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED); - - // -------------------------------------------------------------------- - // Call Expectations - - setupCommonCallExpectationsForConnectProcessing(); - setupCommonCallExpectationsForDisconnectProcessing(); - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); - - // -------------------------------------------------------------------- - // Postconditions - - // The existing token should have been removed - verifyDisplayIsNotConnected(existing.token()); - const auto displayId = Case::Display::DISPLAY_ID::get(); - 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 - - verifyPhysicalDisplayIsConnected(); - - // -------------------------------------------------------------------- - // Cleanup conditions - - EXPECT_CALL(*mComposer, - setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, - IComposerClient::Vsync::DISABLE)) - .WillOnce(Return(Error::NONE)); - EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR)); - }(), - testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected."); -} - -TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAdded) { - using Case = HwcVirtualDisplayCase; - - // -------------------------------------------------------------------- - // Preconditions - - // The HWC supports at least one virtual display - injectMockComposer(1); - - setupCommonPreconditions(); - - // A virtual display was added to the current state, and it has a - // surface(producer) - sp displayToken = new BBinder(); - - DisplayDeviceState state; - state.isSecure = static_cast(Case::Display::SECURE); - - sp surface{new mock::GraphicBufferProducer()}; - state.surface = surface; - mFlinger.mutableCurrentState().displays.add(displayToken, state); - - // -------------------------------------------------------------------- - // Call Expectations - - Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this); - Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this); - - EXPECT_CALL(*surface, query(NATIVE_WINDOW_WIDTH, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::WIDTH), Return(NO_ERROR))); - EXPECT_CALL(*surface, query(NATIVE_WINDOW_HEIGHT, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::HEIGHT), Return(NO_ERROR))); - EXPECT_CALL(*surface, query(NATIVE_WINDOW_FORMAT, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT), - Return(NO_ERROR))); - EXPECT_CALL(*surface, query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR))); - - EXPECT_CALL(*surface, setAsyncMode(true)).Times(1); - - EXPECT_CALL(*mProducer, connect(_, NATIVE_WINDOW_API_EGL, false, _)).Times(1); - EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1); - - Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this); - Case::WideColorSupport::setupComposerCallExpectations(this); - Case::HdrSupport::setupComposerCallExpectations(this); - Case::PerFrameMetadataSupport::setupComposerCallExpectations(this); - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); - - // -------------------------------------------------------------------- - // Postconditions - - // The display device should have been set up in the list of displays. - verifyDisplayIsConnected(displayToken); - - // -------------------------------------------------------------------- - // Cleanup conditions - - EXPECT_CALL(*mComposer, destroyVirtualDisplay(Case::Display::HWC_DISPLAY_ID)) - .WillOnce(Return(Error::NONE)); - EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR)); - - // Cleanup - mFlinger.mutableCurrentState().displays.removeItem(displayToken); - mFlinger.mutableDrawingState().displays.removeItem(displayToken); -} - -TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) { - using Case = HwcVirtualDisplayCase; - - // -------------------------------------------------------------------- - // Preconditions - - // The HWC supports at least one virtual display - injectMockComposer(1); - - setupCommonPreconditions(); - - // A virtual display was added to the current state, but it does not have a - // surface. - sp displayToken = new BBinder(); - - DisplayDeviceState state; - state.isSecure = static_cast(Case::Display::SECURE); - - mFlinger.mutableCurrentState().displays.add(displayToken, state); - - // -------------------------------------------------------------------- - // Call Expectations - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); - - // -------------------------------------------------------------------- - // Postconditions - - // There will not be a display device set up. - EXPECT_FALSE(hasDisplayDevice(displayToken)); - - // The drawing display state will be set from the current display state. - ASSERT_TRUE(hasDrawingDisplayState(displayToken)); - const auto& draw = getDrawingDisplayState(displayToken); - EXPECT_EQ(static_cast(Case::Display::VIRTUAL), draw.isVirtual()); -} - -TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) { - using Case = HwcVirtualDisplayCase; - - // -------------------------------------------------------------------- - // Preconditions - - // A virtual display is set up but is removed from the current state. - const auto displayId = Case::Display::DISPLAY_ID::get(); - ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId)); - mFlinger.mutableHwcDisplayData().try_emplace(displayId); - Case::Display::injectHwcDisplay(this); - auto existing = Case::Display::makeFakeExistingDisplayInjector(this); - existing.inject(); - mFlinger.mutableCurrentState().displays.removeItem(existing.token()); - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); - - // -------------------------------------------------------------------- - // Postconditions - - // The existing token should have been removed - verifyDisplayIsNotConnected(existing.token()); -} - -TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) { - using Case = NonHwcVirtualDisplayCase; - - constexpr ui::LayerStack oldLayerStack = ui::DEFAULT_LAYER_STACK; - constexpr ui::LayerStack newLayerStack{123u}; - - // -------------------------------------------------------------------- - // Preconditions - - // A display is set up - auto display = Case::Display::makeFakeExistingDisplayInjector(this); - display.inject(); - - // There is a change to the layerStack state - display.mutableDrawingDisplayState().layerStack = oldLayerStack; - display.mutableCurrentDisplayState().layerStack = newLayerStack; - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); - - // -------------------------------------------------------------------- - // Postconditions - - EXPECT_EQ(newLayerStack, display.mutableDisplayDevice()->getLayerStack()); -} - -TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) { - using Case = NonHwcVirtualDisplayCase; - - constexpr ui::Rotation oldTransform = ui::ROTATION_0; - constexpr ui::Rotation newTransform = ui::ROTATION_180; - - // -------------------------------------------------------------------- - // Preconditions - - // A display is set up - auto display = Case::Display::makeFakeExistingDisplayInjector(this); - display.inject(); - - // There is a change to the orientation state - display.mutableDrawingDisplayState().orientation = oldTransform; - display.mutableCurrentDisplayState().orientation = newTransform; - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); - - // -------------------------------------------------------------------- - // Postconditions - - EXPECT_EQ(newTransform, display.mutableDisplayDevice()->getOrientation()); -} - -TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackRectChanges) { - using Case = NonHwcVirtualDisplayCase; - - const Rect oldLayerStackRect(0, 0, 0, 0); - const Rect newLayerStackRect(0, 0, 123, 456); - - // -------------------------------------------------------------------- - // Preconditions - - // A display is set up - auto display = Case::Display::makeFakeExistingDisplayInjector(this); - display.inject(); - - // There is a change to the layerStackSpaceRect state - display.mutableDrawingDisplayState().layerStackSpaceRect = oldLayerStackRect; - display.mutableCurrentDisplayState().layerStackSpaceRect = newLayerStackRect; - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); - - // -------------------------------------------------------------------- - // Postconditions - - EXPECT_EQ(newLayerStackRect, display.mutableDisplayDevice()->getLayerStackSpaceRect()); -} - -TEST_F(HandleTransactionLockedTest, processesDisplayRectChanges) { - using Case = NonHwcVirtualDisplayCase; - - const Rect oldDisplayRect(0, 0); - const Rect newDisplayRect(123, 456); - - // -------------------------------------------------------------------- - // Preconditions - - // A display is set up - auto display = Case::Display::makeFakeExistingDisplayInjector(this); - display.inject(); - - // There is a change to the layerStackSpaceRect state - display.mutableDrawingDisplayState().orientedDisplaySpaceRect = oldDisplayRect; - display.mutableCurrentDisplayState().orientedDisplaySpaceRect = newDisplayRect; - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); - - // -------------------------------------------------------------------- - // Postconditions - - EXPECT_EQ(newDisplayRect, display.mutableDisplayDevice()->getOrientedDisplaySpaceRect()); -} - -TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) { - using Case = NonHwcVirtualDisplayCase; - - constexpr int oldWidth = 0; - constexpr int oldHeight = 10; - constexpr int newWidth = 123; - - // -------------------------------------------------------------------- - // Preconditions - - // A display is set up - auto nativeWindow = new mock::NativeWindow(); - auto displaySurface = new compositionengine::mock::DisplaySurface(); - sp buf = new GraphicBuffer(); - auto display = Case::Display::makeFakeExistingDisplayInjector(this); - display.setNativeWindow(nativeWindow); - display.setDisplaySurface(displaySurface); - // Setup injection expectations - EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _)) - .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0))); - EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) - .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0))); - EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1); - EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1); - EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1); - EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1); - display.inject(); - - // There is a change to the layerStackSpaceRect state - display.mutableDrawingDisplayState().width = oldWidth; - display.mutableDrawingDisplayState().height = oldHeight; - display.mutableCurrentDisplayState().width = newWidth; - display.mutableCurrentDisplayState().height = oldHeight; - - // -------------------------------------------------------------------- - // Call Expectations - - EXPECT_CALL(*displaySurface, resizeBuffers(ui::Size(newWidth, oldHeight))).Times(1); - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); -} - -TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) { - using Case = NonHwcVirtualDisplayCase; - - constexpr int oldWidth = 0; - constexpr int oldHeight = 10; - constexpr int newHeight = 123; - - // -------------------------------------------------------------------- - // Preconditions - - // A display is set up - auto nativeWindow = new mock::NativeWindow(); - auto displaySurface = new compositionengine::mock::DisplaySurface(); - sp buf = new GraphicBuffer(); - auto display = Case::Display::makeFakeExistingDisplayInjector(this); - display.setNativeWindow(nativeWindow); - display.setDisplaySurface(displaySurface); - // Setup injection expectations - EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _)) - .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0))); - EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) - .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0))); - EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1); - EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1); - EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1); - EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1); - display.inject(); - - // There is a change to the layerStackSpaceRect state - display.mutableDrawingDisplayState().width = oldWidth; - display.mutableDrawingDisplayState().height = oldHeight; - display.mutableCurrentDisplayState().width = oldWidth; - display.mutableCurrentDisplayState().height = newHeight; - - // -------------------------------------------------------------------- - // Call Expectations - - EXPECT_CALL(*displaySurface, resizeBuffers(ui::Size(oldWidth, newHeight))).Times(1); - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); -} - -TEST_F(HandleTransactionLockedTest, processesDisplaySizeDisplayRectAndLayerStackRectChanges) { - using Case = NonHwcVirtualDisplayCase; - - constexpr uint32_t kOldWidth = 567; - constexpr uint32_t kOldHeight = 456; - const auto kOldSize = Rect(kOldWidth, kOldHeight); - - constexpr uint32_t kNewWidth = 234; - constexpr uint32_t kNewHeight = 123; - const auto kNewSize = Rect(kNewWidth, kNewHeight); - - // -------------------------------------------------------------------- - // Preconditions - - // A display is set up - auto nativeWindow = new mock::NativeWindow(); - auto displaySurface = new compositionengine::mock::DisplaySurface(); - sp buf = new GraphicBuffer(); - auto display = Case::Display::makeFakeExistingDisplayInjector(this); - display.setNativeWindow(nativeWindow); - display.setDisplaySurface(displaySurface); - // Setup injection expectations - EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _)) - .WillOnce(DoAll(SetArgPointee<1>(kOldWidth), Return(0))); - EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) - .WillOnce(DoAll(SetArgPointee<1>(kOldHeight), Return(0))); - display.inject(); - - // There is a change to the layerStackSpaceRect state - display.mutableDrawingDisplayState().width = kOldWidth; - display.mutableDrawingDisplayState().height = kOldHeight; - display.mutableDrawingDisplayState().layerStackSpaceRect = kOldSize; - display.mutableDrawingDisplayState().orientedDisplaySpaceRect = kOldSize; - - display.mutableCurrentDisplayState().width = kNewWidth; - display.mutableCurrentDisplayState().height = kNewHeight; - display.mutableCurrentDisplayState().layerStackSpaceRect = kNewSize; - display.mutableCurrentDisplayState().orientedDisplaySpaceRect = kNewSize; - - // -------------------------------------------------------------------- - // Call Expectations - - EXPECT_CALL(*displaySurface, resizeBuffers(kNewSize.getSize())).Times(1); - - // -------------------------------------------------------------------- - // Invocation - - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); - - EXPECT_EQ(display.mutableDisplayDevice()->getBounds(), kNewSize); - EXPECT_EQ(display.mutableDisplayDevice()->getWidth(), kNewWidth); - EXPECT_EQ(display.mutableDisplayDevice()->getHeight(), kNewHeight); - EXPECT_EQ(display.mutableDisplayDevice()->getOrientedDisplaySpaceRect(), kNewSize); - EXPECT_EQ(display.mutableDisplayDevice()->getLayerStackSpaceRect(), kNewSize); -} - -} // namespace -} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index a1cd448173..d8352ed9d4 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -316,9 +316,9 @@ public: dispSurface, producer); } - auto handleTransactionLocked(uint32_t transactionFlags) { - Mutex::Autolock _l(mFlinger->mStateLock); - return mFlinger->handleTransactionLocked(transactionFlags); + auto commitTransactionsLocked(uint32_t transactionFlags) { + Mutex::Autolock lock(mFlinger->mStateLock); + return mFlinger->commitTransactionsLocked(transactionFlags); } void onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) { @@ -326,7 +326,7 @@ public: } auto setDisplayStateLocked(const DisplayState& s) { - Mutex::Autolock _l(mFlinger->mStateLock); + Mutex::Autolock lock(mFlinger->mStateLock); return mFlinger->setDisplayStateLocked(s); } -- cgit v1.2.3-59-g8ed1b From 31e76ed995d34768f5c4e124965f0f08a12cee5a Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 16 Aug 2021 12:01:57 -0700 Subject: Undo rotation by physical orientation in WindowInfo transforms Some devices have a their display panels installed in a different orientation than the expected default orientation. This can be configured through the build prop ro.surface_flinger.primary_display_orientation, or through other means. Input, framework, and other services are not concerned with the display panel orientation. In this CL, we rotate the transforms sent in WindowInfo by the inverse of the physical orientation, making the window transforms relative to WM's ROTATION_0 instead of the display panel orientation. Bug: 179274888 Bug: 195617582 Bug: 195586068 Test: manual with device that has a non-standard display panel installation Test: atest com.android.launcher3.ui.TaplTestsLauncher3 Change-Id: I727b22c004014355f337da2b753b61c5946667d0 --- services/surfaceflinger/Layer.cpp | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d27b51b345..b76ffc40bc 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2181,11 +2181,11 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTra } const ui::Transform layerTransform = getInputTransform(); - // Transform that takes window coordinates to unrotated display coordinates + // Transform that takes window coordinates to non-rotated display coordinates ui::Transform t = displayTransform * layerTransform; int32_t xSurfaceInset = info.surfaceInset; int32_t ySurfaceInset = info.surfaceInset; - // Bring screenBounds into unrotated space + // Bring screenBounds into non-unrotated space Rect screenBounds = displayTransform.transform(Rect{mScreenBounds}); const float xScale = t.getScaleX(); @@ -2279,17 +2279,34 @@ WindowInfo Layer::fillInputInfo(const DisplayDevice* display) { info.id = sequence; info.displayId = getLayerStack().id; - // Transform that maps from LayerStack space to display space, e.g. rotated to unrotated. + // Transform that maps from LayerStack space to display space, e.g. rotated to non-rotated. // Used when InputFlinger operates in display space. ui::Transform displayTransform; if (display) { - displayTransform = display->getTransform(); - // getOrientation() without masking can contain more-significant bits (eg. ROT_INVALID). - constexpr uint32_t kAllRotationsMask = - ui::Transform::ROT_90 | ui::Transform::ROT_180 | ui::Transform::ROT_270; - info.displayOrientation = displayTransform.getOrientation() & kAllRotationsMask; - info.displayWidth = display->getWidth(); - info.displayHeight = display->getHeight(); + // The physical orientation is set when the orientation of the display panel is different + // than the default orientation of the device. Other services like InputFlinger do not know + // about this, so we do not need to expose the physical orientation of the panel outside of + // SurfaceFlinger. + const ui::Rotation inversePhysicalOrientation = + ui::ROTATION_0 - display->getPhysicalOrientation(); + auto width = display->getWidth(); + auto height = display->getHeight(); + if (inversePhysicalOrientation == ui::ROTATION_90 || + inversePhysicalOrientation == ui::ROTATION_270) { + std::swap(width, height); + } + const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags( + inversePhysicalOrientation), + width, height); + displayTransform = undoPhysicalOrientation * display->getTransform(); + + // Send the inverse of the display orientation so that input can transform points back to + // the rotated display space. + const ui::Rotation inverseOrientation = ui::ROTATION_0 - display->getOrientation(); + info.displayOrientation = ui::Transform::toRotationFlags(inverseOrientation); + + info.displayWidth = width; + info.displayHeight = height; } fillInputFrameInfo(info, displayTransform); -- cgit v1.2.3-59-g8ed1b From 0a39899495675d5a1f84877ff224291d38e544b7 Mon Sep 17 00:00:00 2001 From: chaviw Date: Fri, 13 Aug 2021 10:13:01 -0500 Subject: Add display proto info Currently display bounds are calculated in to layer bounds so when proto files are uploaded, the display bounds are set at the root layer. However, once display bounds are removed from layer bounds calculation, the proto information will be missing display info and will be hard to show a correct visual representation. Add display proto info so winscope can properly show the display area. Test: winscope works Bug: 188792659 Change-Id: I445a892a855c302ab617a9c79bfbf5f217ac5349 --- services/surfaceflinger/Layer.cpp | 10 +++--- services/surfaceflinger/LayerProtoHelper.cpp | 22 ++++++++++-- services/surfaceflinger/LayerProtoHelper.h | 7 +++- services/surfaceflinger/SurfaceFlinger.cpp | 26 +++++++++++++-- services/surfaceflinger/SurfaceFlinger.h | 2 ++ services/surfaceflinger/SurfaceTracing.cpp | 13 +++++--- services/surfaceflinger/SurfaceTracing.h | 1 + services/surfaceflinger/layerproto/Android.bp | 3 +- services/surfaceflinger/layerproto/common.proto | 39 ++++++++++++++++++++++ services/surfaceflinger/layerproto/display.proto | 36 ++++++++++++++++++++ services/surfaceflinger/layerproto/layers.proto | 23 ++----------- .../surfaceflinger/layerproto/layerstrace.proto | 3 ++ 12 files changed, 148 insertions(+), 37 deletions(-) create mode 100644 services/surfaceflinger/layerproto/common.proto create mode 100644 services/surfaceflinger/layerproto/display.proto (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b872c85861..804cf9a3a0 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2016,8 +2016,8 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, if (buffer != nullptr) { LayerProtoHelper::writeToProto(buffer, [&]() { return layerInfo->mutable_active_buffer(); }); - LayerProtoHelper::writeToProto(ui::Transform(getBufferTransform()), - layerInfo->mutable_buffer_transform()); + LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()), + layerInfo->mutable_buffer_transform()); } layerInfo->set_invalidate(contentDirty); layerInfo->set_is_protected(isProtected()); @@ -2031,7 +2031,7 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, layerInfo->set_corner_radius(getRoundedCornerState().radius); layerInfo->set_background_blur_radius(getBackgroundBlurRadius()); layerInfo->set_is_trusted_overlay(isTrustedOverlay()); - LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform()); + LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform()); LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), [&]() { return layerInfo->mutable_position(); }); LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); @@ -2106,8 +2106,8 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet [&]() { return layerInfo->mutable_requested_color(); }); layerInfo->set_flags(state.flags); - LayerProtoHelper::writeToProto(requestedTransform, - layerInfo->mutable_requested_transform()); + LayerProtoHelper::writeToProtoDeprecated(requestedTransform, + layerInfo->mutable_requested_transform()); auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote(); if (parent != nullptr) { diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index 79f7b1f1e8..1062126b58 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -98,8 +98,8 @@ void LayerProtoHelper::writeToProto(const half4 color, std::functionset_type(type); @@ -114,6 +114,22 @@ void LayerProtoHelper::writeToProto(const ui::Transform& transform, } } +void LayerProtoHelper::writeTransformToProto(const ui::Transform& transform, + TransformProto* transformProto) { + const uint32_t type = transform.getType() | (transform.getOrientation() << 8); + transformProto->set_type(type); + + // Rotations that are 90/180/270 have their own type so the transform matrix can be + // reconstructed later. All other rotation have the type UNKNOWN so we need to save the + // transform values in that case. + if (type & (ui::Transform::SCALE | ui::Transform::UNKNOWN)) { + transformProto->set_dsdx(transform.dsdx()); + transformProto->set_dtdx(transform.dtdx()); + transformProto->set_dtdy(transform.dtdy()); + transformProto->set_dsdy(transform.dsdy()); + } +} + void LayerProtoHelper::writeToProto(const sp& buffer, std::function getActiveBufferProto) { if (buffer->getWidth() != 0 || buffer->getHeight() != 0 || buffer->getStride() != 0 || @@ -154,7 +170,7 @@ void LayerProtoHelper::writeToProto( proto->set_has_wallpaper(inputInfo.hasWallpaper); proto->set_global_scale_factor(inputInfo.globalScaleFactor); - LayerProtoHelper::writeToProto(inputInfo.transform, proto->mutable_transform()); + LayerProtoHelper::writeToProtoDeprecated(inputInfo.transform, proto->mutable_transform()); proto->set_replace_touchable_region_with_crop(inputInfo.replaceTouchableRegionWithCrop); auto cropLayer = touchableRegionBounds.promote(); if (cropLayer != nullptr) { diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h index 187ce3d134..36e06471ee 100644 --- a/services/surfaceflinger/LayerProtoHelper.h +++ b/services/surfaceflinger/LayerProtoHelper.h @@ -37,7 +37,12 @@ public: std::function getFloatRectProto); static void writeToProto(const Region& region, std::function getRegionProto); static void writeToProto(const half4 color, std::function getColorProto); - static void writeToProto(const ui::Transform& transform, TransformProto* transformProto); + // This writeToProto for transform is incorrect, but due to backwards compatibility, we can't + // update Layers to use it. Use writeTransformToProto for any new transform proto data. + static void writeToProtoDeprecated(const ui::Transform& transform, + TransformProto* transformProto); + static void writeTransformToProto(const ui::Transform& transform, + TransformProto* transformProto); static void writeToProto(const sp& buffer, std::function getActiveBufferProto); static void writeToProto(const gui::WindowInfo& inputInfo, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 649ddff6fd..5472613348 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -114,6 +114,7 @@ #include "FrameTracer/FrameTracer.h" #include "HdrLayerInfoReporter.h" #include "Layer.h" +#include "LayerProtoHelper.h" #include "LayerRenderArea.h" #include "LayerVector.h" #include "MonitoredProducer.h" @@ -4636,9 +4637,14 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { } if (dumpLayers) { - const LayersProto layersProto = dumpProtoFromMainThread(); + LayersTraceFileProto traceFileProto = SurfaceTracing::createLayersTraceFileProto(); + LayersTraceProto* layersTrace = traceFileProto.add_entry(); + LayersProto layersProto = dumpProtoFromMainThread(); + layersTrace->mutable_layers()->Swap(&layersProto); + dumpDisplayProto(*layersTrace); + if (asProto) { - result.append(layersProto.SerializeAsString()); + result.append(traceFileProto.SerializeAsString()); } else { // Dump info that we need to access from the main thread const auto layerTree = LayerProtoParser::generateLayerTree(layersProto); @@ -4910,6 +4916,22 @@ LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { return layersProto; } +void SurfaceFlinger::dumpDisplayProto(LayersTraceProto& layersTraceProto) const { + for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { + DisplayProto* displayProto = layersTraceProto.add_displays(); + displayProto->set_id(display->getId().value); + displayProto->set_name(display->getDisplayName()); + displayProto->set_layer_stack(display->getLayerStack().id); + LayerProtoHelper::writeSizeToProto(display->getWidth(), display->getHeight(), + [&]() { return displayProto->mutable_size(); }); + LayerProtoHelper::writeToProto(display->getLayerStackSpaceRect(), [&]() { + return displayProto->mutable_layer_stack_space_rect(); + }); + LayerProtoHelper::writeTransformToProto(display->getTransform(), + displayProto->mutable_transform()); + } +} + void SurfaceFlinger::dumpHwc(std::string& result) const { getHwComposer().dump(result); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 33bc17ba73..8381483641 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1174,6 +1174,8 @@ private: LayersProto dumpDrawingStateProto(uint32_t traceFlags) const; void dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + void dumpDisplayProto(LayersTraceProto& layersTraceProto) const; + // Dumps state from HW Composer void dumpHwc(std::string& result) const; LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp index b4d8a9adce..596373732f 100644 --- a/services/surfaceflinger/SurfaceTracing.cpp +++ b/services/surfaceflinger/SurfaceTracing.cpp @@ -137,14 +137,19 @@ status_t SurfaceTracing::Runner::stop() { return writeToFile(); } +LayersTraceFileProto SurfaceTracing::createLayersTraceFileProto() { + LayersTraceFileProto fileProto; + fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | + LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); + return fileProto; +} + status_t SurfaceTracing::Runner::writeToFile() { ATRACE_CALL(); - LayersTraceFileProto fileProto; + LayersTraceFileProto fileProto = createLayersTraceFileProto(); std::string output; - fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | - LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); mBuffer.flush(&fileProto); mBuffer.reset(mConfig.bufferSize); @@ -186,7 +191,7 @@ LayersTraceProto SurfaceTracing::Runner::traceLayers(const char* where) { entry.set_excludes_composition_state(true); } entry.set_missed_entries(mMissedTraceEntries); - + mFlinger.dumpDisplayProto(entry); return entry; } diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index 42a16c64a4..cea1a3324e 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -73,6 +73,7 @@ public: }; void setTraceFlags(uint32_t flags) { mConfig.flags = flags; } bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; } + static LayersTraceFileProto createLayersTraceFileProto(); private: class Runner; diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp index c8a2b5eed6..973a4392a2 100644 --- a/services/surfaceflinger/layerproto/Android.bp +++ b/services/surfaceflinger/layerproto/Android.bp @@ -13,8 +13,7 @@ cc_library { srcs: [ "LayerProtoParser.cpp", - "layers.proto", - "layerstrace.proto", + "*.proto", ], shared_libs: [ diff --git a/services/surfaceflinger/layerproto/common.proto b/services/surfaceflinger/layerproto/common.proto new file mode 100644 index 0000000000..1c73a9f4a8 --- /dev/null +++ b/services/surfaceflinger/layerproto/common.proto @@ -0,0 +1,39 @@ +/* + * Copyright (C) 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. + */ + +syntax = "proto3"; +option optimize_for = LITE_RUNTIME; +package android.surfaceflinger; + +message RectProto { + int32 left = 1; + int32 top = 2; + int32 right = 3; + int32 bottom = 4; +} + +message SizeProto { + int32 w = 1; + int32 h = 2; +} + +message TransformProto { + float dsdx = 1; + float dtdx = 2; + float dsdy = 3; + float dtdy = 4; + int32 type = 5; +} \ No newline at end of file diff --git a/services/surfaceflinger/layerproto/display.proto b/services/surfaceflinger/layerproto/display.proto new file mode 100644 index 0000000000..ee8830e7f2 --- /dev/null +++ b/services/surfaceflinger/layerproto/display.proto @@ -0,0 +1,36 @@ +/* + * Copyright (C) 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. + */ + +syntax = "proto3"; +option optimize_for = LITE_RUNTIME; + +import "frameworks/native/services/surfaceflinger/layerproto/common.proto"; + +package android.surfaceflinger; + +message DisplayProto { + uint64 id = 1; + + string name = 2; + + uint32 layer_stack = 3; + + SizeProto size = 4; + + RectProto layer_stack_space_rect = 5; + + TransformProto transform = 6; +} diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto index 9f4e7d2eb2..057eabb8cc 100644 --- a/services/surfaceflinger/layerproto/layers.proto +++ b/services/surfaceflinger/layerproto/layers.proto @@ -2,6 +2,9 @@ syntax = "proto3"; option optimize_for = LITE_RUNTIME; + +import "frameworks/native/services/surfaceflinger/layerproto/common.proto"; + package android.surfaceflinger; // Contains a list of all layers. @@ -140,31 +143,11 @@ message PositionProto { float y = 2; } -message SizeProto { - int32 w = 1; - int32 h = 2; -} - -message TransformProto { - float dsdx = 1; - float dtdx = 2; - float dsdy = 3; - float dtdy = 4; - int32 type = 5; -} - message RegionProto { reserved 1; // Previously: uint64 id repeated RectProto rect = 2; } -message RectProto { - int32 left = 1; - int32 top = 2; - int32 right = 3; - int32 bottom = 4; -} - message FloatRectProto { float left = 1; float top = 2; diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto index 990f3cffda..13647b669e 100644 --- a/services/surfaceflinger/layerproto/layerstrace.proto +++ b/services/surfaceflinger/layerproto/layerstrace.proto @@ -18,6 +18,7 @@ syntax = "proto2"; option optimize_for = LITE_RUNTIME; import "frameworks/native/services/surfaceflinger/layerproto/layers.proto"; +import "frameworks/native/services/surfaceflinger/layerproto/display.proto"; package android.surfaceflinger; @@ -57,4 +58,6 @@ message LayersTraceProto { /* Number of missed entries since the last entry was recorded. */ optional uint32 missed_entries = 6; + + repeated DisplayProto displays = 7; } -- cgit v1.2.3-59-g8ed1b From edb375df82f6b48688d85c11dbca91adef088bc8 Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Fri, 10 Sep 2021 12:03:42 +0000 Subject: Initialize DrawingState::trustedOverlay to false in constructor To avoid it being initialised to true randomly. Bug: 199483370 Change-Id: I75be2b1d305e22f8a71532b9f5b8ea6c469baaaa --- services/surfaceflinger/Layer.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 804cf9a3a0..f070d8704c 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -134,6 +134,7 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.frameTimelineInfo = {}; mDrawingState.postTime = -1; mDrawingState.destinationFrame.makeInvalid(); + mDrawingState.isTrustedOverlay = false; if (args.flags & ISurfaceComposerClient::eNoColorFill) { // Set an invalid color so there is no color fill. -- cgit v1.2.3-59-g8ed1b From 48f8cb998c61fcad3db9ca7bbebc9e424844e6e2 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 26 Aug 2021 14:05:36 -0700 Subject: Report gui::DisplayInfo to clients with window info changes InputFlinger needs to know specifications about displays such as orientation and projection from SurfaceFlinger to support the MotionEvent#getRaw API, which returns coordinates in logical display space at the moment. Since dispatcher gets window information from SF, we need to send the display information that affects input dispatching at the same time as updating window information to ensure those two pieces of information remain in sync. Instead of sending display information along with each window, we attempt to reduce the amount of information sent through binder by sending DisplayInfo separately to WindowInfos. The newly added DisplayInfo struct should only be used by InputFlinger to support raw coordinates for now, with the goal of removing it altogether in the future. Bug: 179274888 Test: atest libgui_test inputflinger_tests Test: manual, ensure input works Change-Id: I87429ca4ced5f105f49a117c676cba29f8a5c4da --- libs/gui/Android.bp | 8 ++- libs/gui/DisplayInfo.cpp | 70 ++++++++++++++++++++++ libs/gui/WindowInfo.cpp | 17 ++---- libs/gui/WindowInfosListenerReporter.cpp | 5 +- libs/gui/android/gui/DisplayInfo.aidl | 19 ++++++ libs/gui/android/gui/IWindowInfosListener.aidl | 3 +- libs/gui/include/gui/DisplayInfo.h | 46 ++++++++++++++ libs/gui/include/gui/WindowInfo.h | 7 --- libs/gui/include/gui/WindowInfosListener.h | 4 +- libs/gui/include/gui/WindowInfosListenerReporter.h | 4 +- libs/gui/tests/Android.bp | 7 ++- libs/gui/tests/DisplayInfo_test.cpp | 49 +++++++++++++++ libs/gui/tests/WindowInfo_test.cpp | 5 -- .../inputflinger/dispatcher/InputDispatcher.cpp | 52 ++++++++++++---- services/inputflinger/dispatcher/InputDispatcher.h | 7 ++- services/surfaceflinger/DisplayDevice.cpp | 28 +++++++++ services/surfaceflinger/DisplayDevice.h | 4 ++ services/surfaceflinger/Layer.cpp | 33 +--------- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 17 +++++- .../surfaceflinger/WindowInfosListenerInvoker.cpp | 4 +- .../surfaceflinger/WindowInfosListenerInvoker.h | 3 +- .../tests/WindowInfosListener_test.cpp | 4 +- 23 files changed, 311 insertions(+), 87 deletions(-) create mode 100644 libs/gui/DisplayInfo.cpp create mode 100644 libs/gui/android/gui/DisplayInfo.aidl create mode 100644 libs/gui/include/gui/DisplayInfo.h create mode 100644 libs/gui/tests/DisplayInfo_test.cpp (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 326da3a7b5..2d1f5a1694 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -65,11 +65,13 @@ cc_library_static { host_supported: true, srcs: [ ":guiconstants_aidl", + "android/gui/DisplayInfo.aidl", "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", "android/gui/IWindowInfosListener.aidl", "android/gui/IWindowInfosReportedListener.aidl", "android/gui/WindowInfo.aidl", + "DisplayInfo.cpp", "WindowInfo.cpp", ], @@ -90,7 +92,7 @@ cc_library_static { ], aidl: { - export_aidl_headers: true + export_aidl_headers: true, }, include_dirs: [ @@ -135,8 +137,8 @@ cc_library_static { ], aidl: { - export_aidl_headers: true - } + export_aidl_headers: true, + }, } cc_library_shared { diff --git a/libs/gui/DisplayInfo.cpp b/libs/gui/DisplayInfo.cpp new file mode 100644 index 0000000000..52d9540eeb --- /dev/null +++ b/libs/gui/DisplayInfo.cpp @@ -0,0 +1,70 @@ +/* + * 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. + */ + +#define LOG_TAG "DisplayInfo" + +#include +#include +#include + +#include + +namespace android::gui { + +// --- DisplayInfo --- + +status_t DisplayInfo::readFromParcel(const android::Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + float dsdx, dtdx, tx, dtdy, dsdy, ty; + SAFE_PARCEL(parcel->readInt32, &displayId); + SAFE_PARCEL(parcel->readInt32, &logicalWidth); + SAFE_PARCEL(parcel->readInt32, &logicalHeight); + SAFE_PARCEL(parcel->readFloat, &dsdx); + SAFE_PARCEL(parcel->readFloat, &dtdx); + SAFE_PARCEL(parcel->readFloat, &tx); + SAFE_PARCEL(parcel->readFloat, &dtdy); + SAFE_PARCEL(parcel->readFloat, &dsdy); + SAFE_PARCEL(parcel->readFloat, &ty); + + transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); + + return OK; +} + +status_t DisplayInfo::writeToParcel(android::Parcel* parcel) const { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + SAFE_PARCEL(parcel->writeInt32, displayId); + SAFE_PARCEL(parcel->writeInt32, logicalWidth); + SAFE_PARCEL(parcel->writeInt32, logicalHeight); + SAFE_PARCEL(parcel->writeFloat, transform.dsdx()); + SAFE_PARCEL(parcel->writeFloat, transform.dtdx()); + SAFE_PARCEL(parcel->writeFloat, transform.tx()); + SAFE_PARCEL(parcel->writeFloat, transform.dtdy()); + SAFE_PARCEL(parcel->writeFloat, transform.dsdy()); + SAFE_PARCEL(parcel->writeFloat, transform.ty()); + + return OK; +} + +} // namespace android::gui diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index b2ef7aabc9..5f3a726336 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -54,12 +54,11 @@ bool WindowInfo::operator==(const WindowInfo& info) const { info.frameLeft == frameLeft && info.frameTop == frameTop && info.frameRight == frameRight && info.frameBottom == frameBottom && info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor && - info.transform == transform && info.displayOrientation == displayOrientation && - info.displayWidth == displayWidth && info.displayHeight == displayHeight && - info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible && - info.trustedOverlay == trustedOverlay && info.focusable == focusable && - info.touchOcclusionMode == touchOcclusionMode && info.hasWallpaper == hasWallpaper && - info.paused == paused && info.ownerPid == ownerPid && info.ownerUid == ownerUid && + info.transform == transform && info.touchableRegion.hasSameRects(touchableRegion) && + info.visible == visible && info.trustedOverlay == trustedOverlay && + info.focusable == focusable && info.touchOcclusionMode == touchOcclusionMode && + info.hasWallpaper == hasWallpaper && info.paused == paused && + info.ownerPid == ownerPid && info.ownerUid == ownerUid && info.packageName == packageName && info.inputFeatures == inputFeatures && info.displayId == displayId && info.portalToDisplayId == portalToDisplayId && info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && @@ -97,9 +96,6 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeFloat(transform.dtdy()) ?: parcel->writeFloat(transform.dsdy()) ?: parcel->writeFloat(transform.ty()) ?: - parcel->writeUint32(displayOrientation) ?: - parcel->writeInt32(displayWidth) ?: - parcel->writeInt32(displayHeight) ?: parcel->writeBool(visible) ?: parcel->writeBool(focusable) ?: parcel->writeBool(hasWallpaper) ?: @@ -155,9 +151,6 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->readFloat(&dtdy) ?: parcel->readFloat(&dsdy) ?: parcel->readFloat(&ty) ?: - parcel->readUint32(&displayOrientation) ?: - parcel->readInt32(&displayWidth) ?: - parcel->readInt32(&displayHeight) ?: parcel->readBool(&visible) ?: parcel->readBool(&focusable) ?: parcel->readBool(&hasWallpaper) ?: diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp index c00a4389ad..c32b9ab398 100644 --- a/libs/gui/WindowInfosListenerReporter.cpp +++ b/libs/gui/WindowInfosListenerReporter.cpp @@ -19,6 +19,7 @@ namespace android { +using gui::DisplayInfo; using gui::IWindowInfosReportedListener; using gui::WindowInfo; using gui::WindowInfosListener; @@ -65,7 +66,7 @@ status_t WindowInfosListenerReporter::removeWindowInfosListener( } binder::Status WindowInfosListenerReporter::onWindowInfosChanged( - const std::vector& windowInfos, + const std::vector& windowInfos, const std::vector& displayInfos, const sp& windowInfosReportedListener) { std::unordered_set, ISurfaceComposer::SpHash> windowInfosListeners; @@ -78,7 +79,7 @@ binder::Status WindowInfosListenerReporter::onWindowInfosChanged( } for (auto listener : windowInfosListeners) { - listener->onWindowInfosChanged(windowInfos); + listener->onWindowInfosChanged(windowInfos, displayInfos); } if (windowInfosReportedListener) { diff --git a/libs/gui/android/gui/DisplayInfo.aidl b/libs/gui/android/gui/DisplayInfo.aidl new file mode 100644 index 0000000000..30c088525d --- /dev/null +++ b/libs/gui/android/gui/DisplayInfo.aidl @@ -0,0 +1,19 @@ +/* + * 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. + */ + +package android.gui; + +parcelable DisplayInfo cpp_header "gui/DisplayInfo.h"; diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl index d4553ca82d..a5b2762318 100644 --- a/libs/gui/android/gui/IWindowInfosListener.aidl +++ b/libs/gui/android/gui/IWindowInfosListener.aidl @@ -16,11 +16,12 @@ package android.gui; +import android.gui.DisplayInfo; import android.gui.IWindowInfosReportedListener; import android.gui.WindowInfo; /** @hide */ oneway interface IWindowInfosListener { - void onWindowInfosChanged(in WindowInfo[] windowInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener); + void onWindowInfosChanged(in WindowInfo[] windowInfos, in DisplayInfo[] displayInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener); } diff --git a/libs/gui/include/gui/DisplayInfo.h b/libs/gui/include/gui/DisplayInfo.h new file mode 100644 index 0000000000..74f33a2a87 --- /dev/null +++ b/libs/gui/include/gui/DisplayInfo.h @@ -0,0 +1,46 @@ +/* + * 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 +#include +#include + +namespace android::gui { + +/* + * Describes information about a display that can have windows in it. + * + * This should only be used by InputFlinger to support raw coordinates in logical display space. + */ +struct DisplayInfo : public Parcelable { + int32_t displayId = ADISPLAY_ID_NONE; + + // Logical display dimensions. + int32_t logicalWidth = 0; + int32_t logicalHeight = 0; + + // The display transform. This takes display coordinates to logical display coordinates. + ui::Transform transform; + + status_t writeToParcel(android::Parcel*) const override; + + status_t readFromParcel(const android::Parcel*) override; +}; + +} // namespace android::gui \ No newline at end of file diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index f090c63228..7b7c923a58 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -168,13 +168,6 @@ struct WindowInfo : public Parcelable { // Transform applied to individual windows. ui::Transform transform; - // Display orientation as ui::Transform::RotationFlags. Used for compatibility raw coordinates. - uint32_t displayOrientation = ui::Transform::ROT_0; - - // Display size in its natural rotation. Used to rotate raw coordinates for compatibility. - int32_t displayWidth = 0; - int32_t displayHeight = 0; - /* * This is filled in by the WM relative to the frame and then translated * to absolute coordinates by SurfaceFlinger once the frame is computed. diff --git a/libs/gui/include/gui/WindowInfosListener.h b/libs/gui/include/gui/WindowInfosListener.h index 8a70b9bb57..a18a498c5e 100644 --- a/libs/gui/include/gui/WindowInfosListener.h +++ b/libs/gui/include/gui/WindowInfosListener.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include @@ -23,6 +24,7 @@ namespace android::gui { class WindowInfosListener : public virtual RefBase { public: - virtual void onWindowInfosChanged(const std::vector& /*windowInfos*/) = 0; + virtual void onWindowInfosChanged(const std::vector&, + const std::vector&) = 0; }; } // namespace android::gui \ No newline at end of file diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h index 7cb96e0a30..157a804264 100644 --- a/libs/gui/include/gui/WindowInfosListenerReporter.h +++ b/libs/gui/include/gui/WindowInfosListenerReporter.h @@ -21,7 +21,6 @@ #include #include #include -#include #include namespace android { @@ -30,7 +29,8 @@ class ISurfaceComposer; class WindowInfosListenerReporter : public gui::BnWindowInfosListener { public: static sp getInstance(); - binder::Status onWindowInfosChanged(const std::vector& windowInfos, + binder::Status onWindowInfosChanged(const std::vector&, + const std::vector&, const sp&) override; status_t addWindowInfosListener(const sp& windowInfosListener, diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 3d26c3d858..6dd1073879 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -27,6 +27,7 @@ cc_test { "BufferQueue_test.cpp", "CpuConsumer_test.cpp", "EndToEndNativeInputTest.cpp", + "DisplayInfo_test.cpp", "DisplayedContentSampling_test.cpp", "FillBuffer.cpp", "GLTest.cpp", @@ -62,7 +63,7 @@ cc_test { "libinput", "libui", "libutils", - "libnativewindow" + "libnativewindow", ], header_libs: ["libsurfaceflinger_headers"], @@ -117,7 +118,7 @@ cc_test { "libgui", "libui", "libutils", - "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui. + "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui. "libpdx_default_transport", ], @@ -146,5 +147,5 @@ cc_test { "liblog", "libui", "libutils", - ] + ], } diff --git a/libs/gui/tests/DisplayInfo_test.cpp b/libs/gui/tests/DisplayInfo_test.cpp new file mode 100644 index 0000000000..df3329cd52 --- /dev/null +++ b/libs/gui/tests/DisplayInfo_test.cpp @@ -0,0 +1,49 @@ +/* + * 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 + +namespace android { + +using gui::DisplayInfo; + +namespace test { + +TEST(DisplayInfo, Parcelling) { + DisplayInfo info; + info.displayId = 42; + info.logicalWidth = 99; + info.logicalHeight = 78; + info.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1}); + + Parcel p; + info.writeToParcel(&p); + p.setDataPosition(0); + + DisplayInfo info2; + info2.readFromParcel(&p); + ASSERT_EQ(info.displayId, info2.displayId); + ASSERT_EQ(info.logicalWidth, info2.logicalWidth); + ASSERT_EQ(info.logicalHeight, info2.logicalHeight); + ASSERT_EQ(info.transform, info2.transform); +} + +} // namespace test +} // namespace android diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index a4f436cdba..dcdf76fe35 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -60,9 +60,6 @@ TEST(WindowInfo, Parcelling) { i.globalScaleFactor = 0.3; i.alpha = 0.7; i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1}); - i.displayOrientation = ui::Transform::ROT_0; - i.displayWidth = 1000; - i.displayHeight = 2000; i.visible = false; i.focusable = false; i.hasWallpaper = false; @@ -100,8 +97,6 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor); ASSERT_EQ(i.alpha, i2.alpha); ASSERT_EQ(i.transform, i2.transform); - ASSERT_EQ(i.displayWidth, i2.displayWidth); - ASSERT_EQ(i.displayHeight, i2.displayHeight); ASSERT_EQ(i.visible, i2.visible); ASSERT_EQ(i.focusable, i2.focusable); ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 59cb419d2b..84f5a185d1 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -54,6 +54,7 @@ using android::base::HwTimeoutMultiplier; using android::base::Result; using android::base::StringPrintf; +using android::gui::DisplayInfo; using android::gui::FocusRequest; using android::gui::TouchOcclusionMode; using android::gui::WindowInfo; @@ -2444,9 +2445,15 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowHa inputTarget.inputChannel = inputChannel; inputTarget.flags = targetFlags; inputTarget.globalScaleFactor = windowInfo->globalScaleFactor; - inputTarget.displayOrientation = windowInfo->displayOrientation; - inputTarget.displaySize = - int2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight); + const auto& displayInfoIt = mDisplayInfos.find(windowInfo->displayId); + if (displayInfoIt != mDisplayInfos.end()) { + const auto& displayInfo = displayInfoIt->second; + inputTarget.displayOrientation = displayInfo.transform.getOrientation(); + inputTarget.displaySize = int2(displayInfo.logicalWidth, displayInfo.logicalHeight); + } else { + ALOGI_IF(isPerWindowInputRotationEnabled(), + "DisplayInfo not found for window on display: %d", windowInfo->displayId); + } inputTargets.push_back(inputTarget); it = inputTargets.end() - 1; } @@ -4484,6 +4491,7 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( void InputDispatcher::setInputWindows( const std::unordered_map>>& handlesPerDisplay) { + // TODO(b/198444055): Remove setInputWindows from InputDispatcher. { // acquire lock std::scoped_lock _l(mLock); for (const auto& [displayId, handles] : handlesPerDisplay) { @@ -5013,9 +5021,17 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { } if (!mWindowHandlesByDisplay.empty()) { - for (auto& it : mWindowHandlesByDisplay) { - const std::vector> windowHandles = it.second; - dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first); + for (const auto& [displayId, windowHandles] : mWindowHandlesByDisplay) { + dump += StringPrintf(INDENT "Display: %" PRId32 "\n", displayId); + if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) { + const auto& displayInfo = it->second; + dump += StringPrintf(INDENT2 "logicalSize=%dx%d\n", displayInfo.logicalWidth, + displayInfo.logicalHeight); + displayInfo.transform.dump(dump, "transform", INDENT4); + } else { + dump += INDENT2 "No DisplayInfo found!\n"; + } + if (!windowHandles.empty()) { dump += INDENT2 "Windows:\n"; for (size_t i = 0; i < windowHandles.size(); i++) { @@ -5047,13 +5063,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { windowInfo->inputFeatures.string().c_str()); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64 "ms, trustedOverlay=%s, hasToken=%s, " - "touchOcclusionMode=%s, displayOrientation=%d\n", + "touchOcclusionMode=%s\n", windowInfo->ownerPid, windowInfo->ownerUid, millis(windowInfo->dispatchingTimeout), toString(windowInfo->trustedOverlay), toString(windowInfo->token != nullptr), - toString(windowInfo->touchOcclusionMode).c_str(), - windowInfo->displayOrientation); + toString(windowInfo->touchOcclusionMode).c_str()); windowInfo->transform.dump(dump, "transform", INDENT4); } } else { @@ -6099,16 +6114,29 @@ void InputDispatcher::displayRemoved(int32_t displayId) { mLooper->wake(); } -void InputDispatcher::onWindowInfosChanged(const std::vector& windowInfos) { +void InputDispatcher::onWindowInfosChanged(const std::vector& windowInfos, + const std::vector& displayInfos) { // The listener sends the windows as a flattened array. Separate the windows by display for // more convenient parsing. std::unordered_map>> handlesPerDisplay; - for (const auto& info : windowInfos) { handlesPerDisplay.emplace(info.displayId, std::vector>()); handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info)); } - setInputWindows(handlesPerDisplay); + + { // acquire lock + std::scoped_lock _l(mLock); + mDisplayInfos.clear(); + for (const auto& displayInfo : displayInfos) { + mDisplayInfos.emplace(displayInfo.displayId, displayInfo); + } + + for (const auto& [displayId, handles] : handlesPerDisplay) { + setInputWindowsLocked(handles, displayId); + } + } + // Wake up poll loop since it may need to make new input dispatching choices. + mLooper->wake(); } } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 6df333a154..afe4366c32 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -143,7 +143,8 @@ public: void displayRemoved(int32_t displayId) override; - void onWindowInfosChanged(const std::vector& windowInfos) override; + void onWindowInfosChanged(const std::vector&, + const std::vector&) override; private: enum class DropReason { @@ -337,8 +338,10 @@ private: float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock); android::os::BlockUntrustedTouchesMode mBlockUntrustedTouchesMode GUARDED_BY(mLock); - std::unordered_map>> + std::unordered_map>> mWindowHandlesByDisplay GUARDED_BY(mLock); + std::unordered_map mDisplayInfos + GUARDED_BY(mLock); void setInputWindowsLocked( const std::vector>& inputWindowHandles, int32_t displayId) REQUIRES(mLock); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 802a17d981..fd93b2d8f7 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -139,6 +139,34 @@ uint32_t DisplayDevice::getPageFlipCount() const { return mCompositionDisplay->getRenderSurface()->getPageFlipCount(); } +std::pair DisplayDevice::getInputInfo() const { + gui::DisplayInfo info; + info.displayId = getLayerStack().id; + + // The physical orientation is set when the orientation of the display panel is + // different than the default orientation of the device. Other services like + // InputFlinger do not know about this, so we do not need to expose the physical + // orientation of the panel outside of SurfaceFlinger. + const ui::Rotation inversePhysicalOrientation = ui::ROTATION_0 - mPhysicalOrientation; + auto width = getWidth(); + auto height = getHeight(); + if (inversePhysicalOrientation == ui::ROTATION_90 || + inversePhysicalOrientation == ui::ROTATION_270) { + std::swap(width, height); + } + const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags( + inversePhysicalOrientation), + width, height); + const auto& displayTransform = undoPhysicalOrientation * getTransform(); + // Send the inverse display transform to input so it can convert display coordinates to + // logical display. + info.transform = displayTransform.inverse(); + + info.logicalWidth = getLayerStackSpaceRect().width(); + info.logicalHeight = getLayerStackSpaceRect().height(); + return {info, displayTransform}; +} + // ---------------------------------------------------------------------------- void DisplayDevice::setPowerMode(hal::PowerMode mode) { mPowerMode = mode; diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 43a6bd540a..7762054b4a 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -167,6 +167,10 @@ public: return mDeviceProductInfo; } + // Get the DisplayInfo that will be sent to InputFlinger, and the display transform that should + // be applied to all the input windows on the display. + std::pair getInputInfo() const; + /* ------------------------------------------------------------------------ * Display power mode management. */ diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 804cf9a3a0..2376b83c57 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2131,7 +2131,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet if (traceFlags & SurfaceTracing::TRACE_INPUT) { WindowInfo info; if (useDrawing) { - info = fillInputInfo(nullptr); + info = fillInputInfo(ui::Transform()); } else { info = state.inputInfo; } @@ -2265,7 +2265,7 @@ void Layer::fillTouchOcclusionMode(WindowInfo& info) { } } -WindowInfo Layer::fillInputInfo(const DisplayDevice* display) { +WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) { if (!hasInputInfo()) { mDrawingState.inputInfo.name = getName(); mDrawingState.inputInfo.ownerUid = mOwnerUid; @@ -2279,35 +2279,6 @@ WindowInfo Layer::fillInputInfo(const DisplayDevice* display) { info.id = sequence; info.displayId = getLayerStack().id; - // Transform that maps from LayerStack space to display space, e.g. rotated to non-rotated. - // Used when InputFlinger operates in display space. - ui::Transform displayTransform; - if (display) { - // The physical orientation is set when the orientation of the display panel is different - // than the default orientation of the device. Other services like InputFlinger do not know - // about this, so we do not need to expose the physical orientation of the panel outside of - // SurfaceFlinger. - const ui::Rotation inversePhysicalOrientation = - ui::ROTATION_0 - display->getPhysicalOrientation(); - auto width = display->getWidth(); - auto height = display->getHeight(); - if (inversePhysicalOrientation == ui::ROTATION_90 || - inversePhysicalOrientation == ui::ROTATION_270) { - std::swap(width, height); - } - const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags( - inversePhysicalOrientation), - width, height); - displayTransform = undoPhysicalOrientation * display->getTransform(); - - // Send the inverse of the display orientation so that input can transform points back to - // the rotated display space. - const ui::Rotation inverseOrientation = ui::ROTATION_0 - display->getOrientation(); - info.displayOrientation = ui::Transform::toRotationFlags(inverseOrientation); - - info.displayWidth = width; - info.displayHeight = height; - } fillInputFrameInfo(info, displayTransform); // For compatibility reasons we let layers which can receive input diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4200be4898..3c3c7d0b88 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -851,7 +851,7 @@ public: bool getPremultipledAlpha() const; void setInputInfo(const gui::WindowInfo& info); - gui::WindowInfo fillInputInfo(const DisplayDevice*); + gui::WindowInfo fillInputInfo(const ui::Transform& displayTransform); /** * Returns whether this layer has an explicitly set input-info. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 21b889e264..12389d1663 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -169,6 +169,7 @@ using namespace android::sysprop; using android::hardware::power::Boost; using base::StringAppendF; +using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; using ui::ColorMode; @@ -3053,6 +3054,16 @@ bool enablePerWindowInputRotation() { void SurfaceFlinger::notifyWindowInfos() { std::vector windowInfos; + std::vector displayInfos; + std::unordered_map displayTransforms; + + if (enablePerWindowInputRotation()) { + for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { + const auto& [info, transform] = display->getInputInfo(); + displayInfos.emplace_back(info); + displayTransforms.emplace(display.get(), transform); + } + } mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; @@ -3064,9 +3075,11 @@ void SurfaceFlinger::notifyWindowInfos() { // When calculating the screen bounds we ignore the transparent region since it may // result in an unwanted offset. - windowInfos.push_back(layer->fillInputInfo(display)); + const auto it = displayTransforms.find(display); + windowInfos.push_back( + layer->fillInputInfo(it != displayTransforms.end() ? it->second : ui::Transform())); }); - mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, + mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, mInputWindowCommands.syncInputWindows); } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index dc2aa58c9a..b93d127ab8 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -21,6 +21,7 @@ namespace android { +using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; @@ -67,6 +68,7 @@ void WindowInfosListenerInvoker::binderDied(const wp& who) { } void WindowInfosListenerInvoker::windowInfosChanged(const std::vector& windowInfos, + const std::vector& displayInfos, bool shouldSync) { std::unordered_set, ISurfaceComposer::SpHash> windowInfosListeners; @@ -81,7 +83,7 @@ void WindowInfosListenerInvoker::windowInfosChanged(const std::vectoronWindowInfosChanged(windowInfos, + listener->onWindowInfosChanged(windowInfos, displayInfos, shouldSync ? mWindowInfosReportedListener : nullptr); } } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index 5e5796fe2d..ecd797a631 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -33,7 +33,8 @@ public: void addWindowInfosListener(const sp& windowInfosListener); void removeWindowInfosListener(const sp& windowInfosListener); - void windowInfosChanged(const std::vector& windowInfos, bool shouldSync); + void windowInfosChanged(const std::vector&, + const std::vector&, bool shouldSync); protected: void binderDied(const wp& who) override; diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp index de116f29ca..0069111e09 100644 --- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp +++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp @@ -22,6 +22,7 @@ namespace android { using Transaction = SurfaceComposerClient::Transaction; +using gui::DisplayInfo; using gui::WindowInfo; class WindowInfosListenerTest : public ::testing::Test { @@ -40,7 +41,8 @@ protected: struct SyncWindowInfosListener : public gui::WindowInfosListener { public: - void onWindowInfosChanged(const std::vector& windowInfos) override { + void onWindowInfosChanged(const std::vector& windowInfos, + const std::vector&) override { windowInfosPromise.set_value(windowInfos); } -- cgit v1.2.3-59-g8ed1b From 9cf4a4d4e57d059a4e4119f0a8f2a8be237f28c2 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 17 Sep 2021 12:16:08 -0700 Subject: SurfaceControl: Add setDropInputMode api Introduces an API to drop input events on this SurfaceControl. This policy will be inherited by its children. The caller must hold the ACCESS_SURFACE_FLINGER permission. Options include: ALL: SurfaceControl and its children will not receive any input regardless of whether it has a valid input channel. OBSCURED: SurfaceControl and its children will not receive any input if the layer is obscured, cropped by its parent or translucent. These policies are used to enable features that allow for a less trusted interaction model between apps. See the bug for more details. Test: atest libgui_test InputDispatcherDropInputFeatureTest Bug:197364677 Change-Id: I443741d5ab51a45d37fb865f11c433c436d96c1e --- libs/gui/Android.bp | 1 + libs/gui/LayerState.cpp | 12 +++++++- libs/gui/SurfaceComposerClient.cpp | 15 ++++++++++ libs/gui/android/gui/DropInputMode.aidl | 45 ++++++++++++++++++++++++++++ libs/gui/include/gui/LayerState.h | 5 ++++ libs/gui/include/gui/SurfaceComposerClient.h | 1 + services/surfaceflinger/Layer.cpp | 9 ++++++ services/surfaceflinger/Layer.h | 5 ++++ services/surfaceflinger/SurfaceFlinger.cpp | 10 +++++++ 9 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 libs/gui/android/gui/DropInputMode.aidl (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 2d1f5a1694..8c359c7756 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -55,6 +55,7 @@ cc_library_headers { filegroup { name: "guiconstants_aidl", srcs: [ + "android/gui/DropInputMode.aidl", "android/**/TouchOcclusionMode.aidl", ], } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 1fd9d13902..a419a63056 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -69,7 +69,8 @@ layer_state_t::layer_state_t() isTrustedOverlay(false), bufferCrop(Rect::INVALID_RECT), destinationFrame(Rect::INVALID_RECT), - releaseBufferListener(nullptr) { + releaseBufferListener(nullptr), + dropInputMode(gui::DropInputMode::NONE) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; hdrMetadata.validTypes = 0; @@ -174,6 +175,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeBool, isTrustedOverlay); SAFE_PARCEL(output.writeStrongBinder, releaseBufferEndpoint); + SAFE_PARCEL(output.writeUint32, static_cast(dropInputMode)); return NO_ERROR; } @@ -304,6 +306,10 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readBool, &isTrustedOverlay); SAFE_PARCEL(input.readNullableStrongBinder, &releaseBufferEndpoint); + + uint32_t mode; + SAFE_PARCEL(input.readUint32, &mode); + dropInputMode = static_cast(mode); return NO_ERROR; } @@ -558,6 +564,10 @@ void layer_state_t::merge(const layer_state_t& other) { if (other.what & eProducerDisconnect) { what |= eProducerDisconnect; } + if (other.what & eDropInputModeChanged) { + what |= eDropInputModeChanged; + dropInputMode = other.dropInputMode; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIX64 " what=0x%" PRIX64 " unmerged flags=0x%" PRIX64, diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 1bca6f9167..64361db41e 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1739,6 +1739,21 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesti return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDropInputMode( + const sp& sc, gui::DropInputMode mode) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eDropInputModeChanged; + s->dropInputMode = mode; + + registerSurfaceControlForCallback(sc); + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { diff --git a/libs/gui/android/gui/DropInputMode.aidl b/libs/gui/android/gui/DropInputMode.aidl new file mode 100644 index 0000000000..2b31744ca2 --- /dev/null +++ b/libs/gui/android/gui/DropInputMode.aidl @@ -0,0 +1,45 @@ +/** + * Copyright (c) 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. + */ + +package android.gui; + + +/** + * Input event drop modes: Input event drop options for windows and its children. + * + * @hide + */ +@Backing(type="int") +enum DropInputMode { + /** + * Default mode, input events are sent to the target as usual. + */ + NONE, + + /** + * Window and its children will not receive any input even if it has a valid input channel. + * Touches and keys will be dropped. If a window is focused, it will remain focused but will + * not receive any keys. If the window has a touchable region and is the target of an input + * event, the event will be dropped and will not go to the window behind. ref: b/197296414 + */ + ALL, + + /** + * Similar to DROP but input events are only dropped if the window is considered to be + * obscured. ref: b/197364677 + */ + OBSCURED +} diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index f14127c9de..b27102bcce 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -118,6 +119,7 @@ struct layer_state_t { eAutoRefreshChanged = 0x1000'00000000, eStretchChanged = 0x2000'00000000, eTrustedOverlayChanged = 0x4000'00000000, + eDropInputModeChanged = 0x8000'00000000, }; layer_state_t(); @@ -248,6 +250,9 @@ struct layer_state_t { // releaseCallbackId and release fence to all listeners so we store which listener the setBuffer // was called with. sp releaseBufferEndpoint; + + // Force inputflinger to drop all input events for the layer and its children. + gui::DropInputMode dropInputMode; }; struct ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index baa6878414..ffd0244275 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -562,6 +562,7 @@ public: Transaction& setBufferCrop(const sp& sc, const Rect& bufferCrop); Transaction& setDestinationFrame(const sp& sc, const Rect& destinationFrame); + Transaction& setDropInputMode(const sp& sc, gui::DropInputMode mode); status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index ef6f115fdc..d549fe9966 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -135,6 +135,7 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.postTime = -1; mDrawingState.destinationFrame.makeInvalid(); mDrawingState.isTrustedOverlay = false; + mDrawingState.dropInputMode = gui::DropInputMode::NONE; if (args.flags & ISurfaceComposerClient::eNoColorFill) { // Set an invalid color so there is no color fill. @@ -2541,6 +2542,14 @@ wp Layer::fromHandle(const sp& handleBinder) { return handle->owner; } +bool Layer::setDropInputMode(gui::DropInputMode mode) { + if (mDrawingState.dropInputMode == mode) { + return false; + } + mDrawingState.dropInputMode = mode; + return true; +} + // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 3c3c7d0b88..b70d5d474c 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -17,6 +17,7 @@ #pragma once +#include #include #include #include @@ -277,6 +278,8 @@ public: Rect destinationFrame; sp releaseBufferEndpoint; + + gui::DropInputMode dropInputMode; }; /* @@ -442,6 +445,8 @@ public: virtual bool setFrameRateSelectionPriority(int32_t priority); virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint); virtual void setAutoRefresh(bool /* autoRefresh */) {} + bool setDropInputMode(gui::DropInputMode); + // If the variable is not set on the layer, it traverses up the tree to inherit the frame // rate priority from its parent. virtual int32_t getFrameRateSelectionPriority() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5a881a3dfe..5aa0b87e22 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4147,6 +4147,16 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } + if (what & layer_state_t::eDropInputModeChanged) { + if (privileged) { + if (layer->setDropInputMode(s.dropInputMode)) { + flags |= eTraversalNeeded; + mInputInfoChanged = true; + } + } else { + ALOGE("Attempt to update DropInputMode without permission ACCESS_SURFACE_FLINGER"); + } + } // This has to happen after we reparent children because when we reparent to null we remove // child layers from current state and remove its relative z. If the children are reparented in // the same transaction, then we have to make sure we reparent the children first so we do not -- cgit v1.2.3-59-g8ed1b From a066d908f6fe28e63ae49327b57fcd31d63fba2d Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 13 Sep 2021 18:40:17 -0700 Subject: SurfaceFlinger: Implement drop input modes ALL: If this mode is set on a layer, set the DROP_INPUT feature flag on the layer and its children if it has a valid input channel. This will ensure these layers will not be able to receive any input. OBSCURED: If this mode is set, set the DROP_INPUT feature flag on the layer and its children if they have a valid input channel and they are considered occluded. This can happen if the layer has a alpha set by it's parent OR if its buffer has been cropped by its parent. Otherwise, the input feature flag DROP_INPUT_IF_OBSCURED flag will be set so inputflinger can decide to drop input based on occlusion. Test: atest libgui_test InputDispatcherDropInputFeatureTest Bug: 197364677 Change-Id: Ibce11ee7df5b5c8c226ebfab29574a99cd656f6d --- libs/gui/tests/EndToEndNativeInputTest.cpp | 173 ++++++++++++++++++++++++++++- services/surfaceflinger/Layer.cpp | 69 ++++++++++++ services/surfaceflinger/Layer.h | 2 + 3 files changed, 240 insertions(+), 4 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index fc84c1b619..78a8b429c1 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -24,6 +24,7 @@ #include +#include #include #include @@ -120,8 +121,8 @@ public: return std::make_unique(surfaceControl, width, height); } - InputEvent* consumeEvent() { - waitForEventAvailable(); + InputEvent *consumeEvent(int timeoutMs = 3000) { + waitForEventAvailable(timeoutMs); InputEvent *ev; uint32_t seqId; @@ -178,6 +179,24 @@ public: EXPECT_EQ(flags, mev->getFlags() & flags); } + void expectKey(uint32_t keycode) { + InputEvent *ev = consumeEvent(); + ASSERT_NE(ev, nullptr); + ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, ev->getType()); + KeyEvent *keyEvent = static_cast(ev); + EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, keyEvent->getAction()); + EXPECT_EQ(keycode, keyEvent->getKeyCode()); + EXPECT_EQ(0, keyEvent->getFlags() & VERIFIED_KEY_EVENT_FLAGS); + + ev = consumeEvent(); + ASSERT_NE(ev, nullptr); + ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, ev->getType()); + keyEvent = static_cast(ev); + EXPECT_EQ(AMOTION_EVENT_ACTION_UP, keyEvent->getAction()); + EXPECT_EQ(keycode, keyEvent->getKeyCode()); + EXPECT_EQ(0, keyEvent->getFlags() & VERIFIED_KEY_EVENT_FLAGS); + } + virtual ~InputSurface() { mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken()); } @@ -215,12 +234,12 @@ public: } private: - void waitForEventAvailable() { + void waitForEventAvailable(int timeoutMs) { struct pollfd fd; fd.fd = mClientChannel->getFd(); fd.events = POLLIN; - poll(&fd, 1, 3000); + poll(&fd, 1, timeoutMs); } void populateInputInfo(int width, int height) { @@ -363,6 +382,14 @@ void injectTap(int x, int y) { } } +void injectKey(uint32_t keycode) { + char *buf1; + asprintf(&buf1, "%d", keycode); + if (fork() == 0) { + execlp("input", "input", "keyevent", buf1, NULL); + } +} + TEST_F(InputSurfacesTest, can_receive_input) { std::unique_ptr surface = makeSurface(100, 100); surface->showAt(100, 100); @@ -614,6 +641,9 @@ TEST_F(InputSurfacesTest, can_be_focused) { surface->requestFocus(); surface->assertFocusChange(true); + + injectKey(AKEYCODE_V); + surface->expectKey(AKEYCODE_V); } TEST_F(InputSurfacesTest, rotate_surface) { @@ -781,4 +811,139 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) { surface->expectTap(1, 1); } +TEST_F(InputSurfacesTest, strict_unobscured_input_unobscured_window) { + std::unique_ptr surface = makeSurface(100, 100); + surface->doTransaction( + [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); + surface->showAt(100, 100); + + injectTap(101, 101); + + EXPECT_NE(surface->consumeEvent(), nullptr); + EXPECT_NE(surface->consumeEvent(), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + surface->expectKey(AKEYCODE_V); +} + +TEST_F(InputSurfacesTest, strict_unobscured_input_scaled_without_crop_window) { + std::unique_ptr surface = makeSurface(100, 100); + surface->doTransaction([&](auto &t, auto &sc) { + t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); + t.setMatrix(sc, 2.0, 0, 0, 2.0); + }); + surface->showAt(100, 100); + + injectTap(101, 101); + + EXPECT_NE(surface->consumeEvent(), nullptr); + EXPECT_NE(surface->consumeEvent(), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + surface->expectKey(AKEYCODE_V); +} + +TEST_F(InputSurfacesTest, strict_unobscured_input_obscured_window) { + std::unique_ptr surface = makeSurface(100, 100); + surface->mInputInfo.ownerUid = 11111; + surface->doTransaction( + [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); + surface->showAt(100, 100); + std::unique_ptr obscuringSurface = makeSurface(100, 100); + obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + obscuringSurface->mInputInfo.ownerUid = 22222; + obscuringSurface->showAt(100, 100); + injectTap(101, 101); + EXPECT_EQ(surface->consumeEvent(100), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + EXPECT_EQ(surface->consumeEvent(100), nullptr); +} + +TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) { + std::unique_ptr surface = makeSurface(100, 100); + surface->mInputInfo.ownerUid = 11111; + surface->doTransaction( + [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); + surface->showAt(100, 100); + std::unique_ptr obscuringSurface = makeSurface(100, 100); + obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + obscuringSurface->mInputInfo.ownerUid = 22222; + obscuringSurface->showAt(190, 190); + + injectTap(101, 101); + + EXPECT_EQ(surface->consumeEvent(100), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + EXPECT_EQ(surface->consumeEvent(100), nullptr); +} + +TEST_F(InputSurfacesTest, strict_unobscured_input_alpha_window) { + std::unique_ptr parentSurface = makeSurface(300, 300); + parentSurface->showAt(0, 0, Rect(0, 0, 300, 300)); + + std::unique_ptr surface = makeSurface(100, 100); + surface->showAt(100, 100); + surface->doTransaction([&](auto &t, auto &sc) { + t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); + t.reparent(sc, parentSurface->mSurfaceControl); + t.setAlpha(parentSurface->mSurfaceControl, 0.9f); + }); + + injectTap(101, 101); + + EXPECT_EQ(surface->consumeEvent(100), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + EXPECT_EQ(surface->consumeEvent(100), nullptr); +} + +TEST_F(InputSurfacesTest, strict_unobscured_input_cropped_window) { + std::unique_ptr parentSurface = makeSurface(300, 300); + parentSurface->showAt(0, 0, Rect(0, 0, 300, 300)); + + std::unique_ptr surface = makeSurface(100, 100); + surface->doTransaction([&](auto &t, auto &sc) { + t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); + t.reparent(sc, parentSurface->mSurfaceControl); + t.setCrop(parentSurface->mSurfaceControl, Rect(10, 10, 100, 100)); + }); + surface->showAt(100, 100); + + injectTap(111, 111); + + EXPECT_EQ(surface->consumeEvent(100), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + EXPECT_EQ(surface->consumeEvent(100), nullptr); +} + +TEST_F(InputSurfacesTest, drop_input_policy) { + std::unique_ptr surface = makeSurface(100, 100); + surface->doTransaction( + [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::ALL); }); + surface->showAt(100, 100); + + injectTap(101, 101); + + EXPECT_EQ(surface->consumeEvent(100), nullptr); + + surface->requestFocus(); + surface->assertFocusChange(true); + injectKey(AKEYCODE_V); + EXPECT_EQ(surface->consumeEvent(100), nullptr); +} } // namespace android::test diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 4050dd5400..10391a2b1f 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2288,6 +2288,74 @@ void Layer::fillTouchOcclusionMode(WindowInfo& info) { } } +gui::DropInputMode Layer::getDropInputMode() const { + gui::DropInputMode mode = mDrawingState.dropInputMode; + if (mode == gui::DropInputMode::ALL) { + return mode; + } + sp parent = mDrawingParent.promote(); + if (parent) { + gui::DropInputMode parentMode = parent->getDropInputMode(); + if (parentMode != gui::DropInputMode::NONE) { + return parentMode; + } + } + return mode; +} + +void Layer::handleDropInputMode(gui::WindowInfo& info) const { + if (mDrawingState.inputInfo.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL)) { + return; + } + + // Check if we need to drop input unconditionally + gui::DropInputMode dropInputMode = getDropInputMode(); + if (dropInputMode == gui::DropInputMode::ALL) { + info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + ALOGV("Dropping input for %s as requested by policy.", getDebugName()); + return; + } + + // Check if we need to check if the window is obscured by parent + if (dropInputMode != gui::DropInputMode::OBSCURED) { + return; + } + + // Check if the parent has set an alpha on the layer + sp parent = mDrawingParent.promote(); + if (parent && parent->getAlpha() != 1.0_hf) { + info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(), + static_cast(getAlpha())); + } + + // Check if the parent has cropped the buffer + Rect bufferSize = getCroppedBufferSize(getDrawingState()); + if (!bufferSize.isValid()) { + info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED; + return; + } + + // Screenbounds are the layer bounds cropped by parents, transformed to screenspace. + // To check if the layer has been cropped, we take the buffer bounds, apply the local + // layer crop and apply the same set of transforms to move to screenspace. If the bounds + // match then the layer has not been cropped by its parents. + Rect bufferInScreenSpace(getTransform().transform(bufferSize)); + bool croppedByParent = bufferInScreenSpace != Rect{mScreenBounds}; + + if (croppedByParent) { + info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + ALOGV("Dropping input for %s as requested by policy because buffer is cropped by parent", + getDebugName()); + } else { + // If the layer is not obscured by its parents (by setting an alpha or crop), then only drop + // input if the window is obscured. This check should be done in surfaceflinger but the + // logic currently resides in inputflinger. So pass the if_obscured check to input to only + // drop input events if the window is obscured. + info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED; + } +} + WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) { if (!hasInputInfo()) { mDrawingState.inputInfo.name = getName(); @@ -2315,6 +2383,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) { info.visible = hasInputInfo() ? canReceiveInput() : isVisible(); info.alpha = getAlpha(); fillTouchOcclusionMode(info); + handleDropInputMode(info); auto cropLayer = mDrawingState.touchableRegionCrop.promote(); if (info.replaceTouchableRegionWithCrop) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 067036a014..7b9303fa58 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -1063,6 +1063,8 @@ private: bool setFrameRateForLayerTree(FrameRate); void setZOrderRelativeOf(const wp& relativeOf); bool isTrustedOverlay() const; + gui::DropInputMode getDropInputMode() const; + void handleDropInputMode(gui::WindowInfo& info) const; // 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. -- cgit v1.2.3-59-g8ed1b From 16a938f8da032c60e5e243838c1fa214d78908c5 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 24 Sep 2021 07:14:54 -0700 Subject: SurfaceFlinger: Drop input for blacked out layers If the window will be blacked out on a display because the display does not have the secure flag and the layer has the secure flag set, then drop input. Test: atest libgui_test Fixes: 200842159 Change-Id: Idfe245b0f0091e0cafc15c83b25a9d0fd7364174 --- libs/gui/tests/EndToEndNativeInputTest.cpp | 101 +++++++++++++++++++++++++---- services/surfaceflinger/Layer.cpp | 10 ++- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 19 +++--- 4 files changed, 108 insertions(+), 24 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 78a8b429c1..16208a7773 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -220,7 +220,7 @@ public: t.apply(true); } - void requestFocus() { + void requestFocus(int displayId = ADISPLAY_ID_DEFAULT) { SurfaceComposerClient::Transaction t; FocusRequest request; request.token = mInputInfo.token; @@ -228,7 +228,7 @@ public: request.focusedToken = nullptr; request.focusedWindowName = ""; request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC); - request.displayId = 0; + request.displayId = displayId; t.setFocusedWindow(request); t.apply(true); } @@ -255,11 +255,6 @@ private: mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height)); - // TODO: Fill in from SF? - mInputInfo.ownerPid = 11111; - mInputInfo.ownerUid = 11111; - mInputInfo.displayId = 0; - InputApplicationInfo aInfo; aInfo.token = new BBinder(); aInfo.name = "Test app info"; @@ -373,23 +368,33 @@ public: int32_t mBufferPostDelay; }; -void injectTap(int x, int y) { - char *buf1, *buf2; +void injectTapOnDisplay(int x, int y, int displayId) { + char *buf1, *buf2, *bufDisplayId; asprintf(&buf1, "%d", x); asprintf(&buf2, "%d", y); + asprintf(&bufDisplayId, "%d", displayId); if (fork() == 0) { - execlp("input", "input", "tap", buf1, buf2, NULL); + execlp("input", "input", "-d", bufDisplayId, "tap", buf1, buf2, NULL); } } -void injectKey(uint32_t keycode) { - char *buf1; +void injectTap(int x, int y) { + injectTapOnDisplay(x, y, ADISPLAY_ID_DEFAULT); +} + +void injectKeyOnDisplay(uint32_t keycode, int displayId) { + char *buf1, *bufDisplayId; asprintf(&buf1, "%d", keycode); + asprintf(&bufDisplayId, "%d", displayId); if (fork() == 0) { - execlp("input", "input", "keyevent", buf1, NULL); + execlp("input", "input", "-d", bufDisplayId, "keyevent", buf1, NULL); } } +void injectKey(uint32_t keycode) { + injectKeyOnDisplay(keycode, ADISPLAY_ID_NONE); +} + TEST_F(InputSurfacesTest, can_receive_input) { std::unique_ptr surface = makeSurface(100, 100); surface->showAt(100, 100); @@ -946,4 +951,74 @@ TEST_F(InputSurfacesTest, drop_input_policy) { injectKey(AKEYCODE_V); EXPECT_EQ(surface->consumeEvent(100), nullptr); } + +class MultiDisplayTests : public InputSurfacesTest { +public: + MultiDisplayTests() : InputSurfacesTest() { ProcessState::self()->startThreadPool(); } + void TearDown() { + if (mVirtualDisplay) { + SurfaceComposerClient::destroyDisplay(mVirtualDisplay); + } + InputSurfacesTest::TearDown(); + } + + void createDisplay(int32_t width, int32_t height, bool isSecure, ui::LayerStack layerStack) { + sp consumer; + BufferQueue::createBufferQueue(&mProducer, &consumer); + consumer->setConsumerName(String8("Virtual disp consumer")); + consumer->setDefaultBufferSize(width, height); + + mVirtualDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), isSecure); + SurfaceComposerClient::Transaction t; + t.setDisplaySurface(mVirtualDisplay, mProducer); + t.setDisplayFlags(mVirtualDisplay, 0x01 /* DisplayDevice::eReceivesInput */); + t.setDisplayLayerStack(mVirtualDisplay, layerStack); + t.apply(true); + } + + sp mVirtualDisplay; + sp mProducer; +}; + +TEST_F(MultiDisplayTests, drop_input_for_secure_layer_on_nonsecure_display) { + ui::LayerStack layerStack = ui::LayerStack::fromValue(42); + createDisplay(1000, 1000, false /*isSecure*/, layerStack); + std::unique_ptr surface = makeSurface(100, 100); + surface->doTransaction([&](auto &t, auto &sc) { + t.setFlags(sc, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure); + t.setLayerStack(sc, layerStack); + }); + surface->showAt(100, 100); + + injectTap(101, 101); + + EXPECT_EQ(surface->consumeEvent(100), nullptr); + + surface->requestFocus(layerStack.id); + surface->assertFocusChange(true); + injectKeyOnDisplay(AKEYCODE_V, layerStack.id); + EXPECT_EQ(surface->consumeEvent(100), nullptr); +} + +TEST_F(MultiDisplayTests, dont_drop_input_for_secure_layer_on_secure_display) { + ui::LayerStack layerStack = ui::LayerStack::fromValue(42); + createDisplay(1000, 1000, true /*isSecure*/, layerStack); + std::unique_ptr surface = makeSurface(100, 100); + surface->doTransaction([&](auto &t, auto &sc) { + t.setFlags(sc, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure); + t.setLayerStack(sc, layerStack); + }); + surface->showAt(100, 100); + + injectTapOnDisplay(101, 101, layerStack.id); + EXPECT_NE(surface->consumeEvent(), nullptr); + EXPECT_NE(surface->consumeEvent(), nullptr); + + surface->requestFocus(layerStack.id); + surface->assertFocusChange(true); + injectKeyOnDisplay(AKEYCODE_V, layerStack.id); + + surface->expectKey(AKEYCODE_V); +} + } // namespace android::test diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 10391a2b1f..87afa222e8 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2154,7 +2154,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet if (traceFlags & SurfaceTracing::TRACE_INPUT) { WindowInfo info; if (useDrawing) { - info = fillInputInfo(ui::Transform()); + info = fillInputInfo(ui::Transform(), /* displayIsSecure */ true); } else { info = state.inputInfo; } @@ -2356,7 +2356,7 @@ void Layer::handleDropInputMode(gui::WindowInfo& info) const { } } -WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) { +WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool displayIsSecure) { if (!hasInputInfo()) { mDrawingState.inputInfo.name = getName(); mDrawingState.inputInfo.ownerUid = mOwnerUid; @@ -2385,6 +2385,12 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) { fillTouchOcclusionMode(info); handleDropInputMode(info); + // If the window will be blacked out on a display because the display does not have the secure + // flag and the layer has the secure flag set, then drop input. + if (!displayIsSecure && isSecure()) { + info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + } + auto cropLayer = mDrawingState.touchableRegionCrop.promote(); if (info.replaceTouchableRegionWithCrop) { const Rect bounds(cropLayer ? cropLayer->mScreenBounds : mScreenBounds); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 7b9303fa58..8c281d53e4 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -854,7 +854,7 @@ public: bool getPremultipledAlpha() const; void setInputInfo(const gui::WindowInfo& info); - gui::WindowInfo fillInputInfo(const ui::Transform& displayTransform); + gui::WindowInfo fillInputInfo(const ui::Transform& displayTransform, bool displayIsSecure); /** * Returns whether this layer has an explicitly set input-info. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d4db33c3e6..88715e36aa 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3089,16 +3089,19 @@ void SurfaceFlinger::notifyWindowInfos() { mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; - const DisplayDevice* display = nullptr; + const DisplayDevice* display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get(); + ui::Transform displayTransform = ui::Transform(); + if (enablePerWindowInputRotation()) { - display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get(); + // When calculating the screen bounds we ignore the transparent region since it may + // result in an unwanted offset. + const auto it = displayTransforms.find(display); + if (it != displayTransforms.end()) { + displayTransform = it->second; + } } - - // When calculating the screen bounds we ignore the transparent region since it may - // result in an unwanted offset. - const auto it = displayTransforms.find(display); - windowInfos.push_back( - layer->fillInputInfo(it != displayTransforms.end() ? it->second : ui::Transform())); + const bool displayIsSecure = !display || display->isSecure(); + windowInfos.push_back(layer->fillInputInfo(displayTransform, displayIsSecure)); }); mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, mInputWindowCommands.syncInputWindows); -- cgit v1.2.3-59-g8ed1b From b4ba8f5c269b6d82a09f779dc3336ece4c04c053 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Mon, 27 Sep 2021 18:20:58 -0700 Subject: SF: Fix -Wunused-but-set-variable Soong appends -Wno-error=unused-but-set-variable, negating SF's -Werror. - The type and appId variables are VR remnants. - TimeStats::canAddNewAggregatedStats compared apples and oranges. Bug: 129481165 Test: No warnings on clean build Change-Id: I071e71148a269bf9ab9a5e930a775b4ae6564916 --- services/surfaceflinger/BufferLayerConsumer.cpp | 2 +- services/surfaceflinger/Layer.cpp | 14 -------------- services/surfaceflinger/TimeStats/TimeStats.cpp | 2 +- 3 files changed, 2 insertions(+), 16 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 96b22478ab..c79fa1104c 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -438,7 +438,7 @@ void BufferLayerConsumer::onDisconnect() { } void BufferLayerConsumer::onSidebandStreamChanged() { - FrameAvailableListener* unsafeFrameAvailableListener = nullptr; + [[maybe_unused]] FrameAvailableListener* unsafeFrameAvailableListener = nullptr; { Mutex::Autolock lock(mFrameAvailableMutex); unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get(); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 87afa222e8..57837d43f9 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -426,20 +426,6 @@ void Layer::prepareBasicGeometryCompositionState() { void Layer::prepareGeometryCompositionState() { const auto& drawingState{getDrawingState()}; - - int type = drawingState.metadata.getInt32(METADATA_WINDOW_TYPE, 0); - int appId = drawingState.metadata.getInt32(METADATA_OWNER_UID, 0); - sp parent = mDrawingParent.promote(); - if (parent.get()) { - auto& parentState = parent->getDrawingState(); - const int parentType = parentState.metadata.getInt32(METADATA_WINDOW_TYPE, 0); - const int parentAppId = parentState.metadata.getInt32(METADATA_OWNER_UID, 0); - if (parentType > 0 && parentAppId > 0) { - type = parentType; - appId = parentAppId; - } - } - auto* compositionState = editCompositionState(); compositionState->geomBufferSize = getBufferSize(drawingState); diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 7c1f21f9e4..bf2038b277 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -564,7 +564,7 @@ bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName layerRecords += record.second.stats.size(); } - return mTimeStats.stats.size() < MAX_NUM_LAYER_STATS; + return layerRecords < MAX_NUM_LAYER_STATS; } void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, -- cgit v1.2.3-59-g8ed1b From cbdb79a195e6c690e16948a7e7c3abbd36414b17 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Fri, 11 Jun 2021 16:10:45 -0700 Subject: Layer: Use raw pointers for Current/Drawing parent We should only be reading/writing this from the main thread and likewise we only delete layers on the main thread and so using raw pointers and managing the lifetime from the Layer destructor will be safe. This significantly decreases overhead in various code that traverses via parent (getAlpha, isVisible, etc...). Test: Existing tests pass. simpleperf Bug: 186200583 Change-Id: I45745f7c865177ddfe9105d1440a9fa8f3470823 --- services/surfaceflinger/BufferLayer.cpp | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 2 +- services/surfaceflinger/Layer.cpp | 77 ++++++++++++---------- services/surfaceflinger/Layer.h | 6 +- services/surfaceflinger/SurfaceFlinger.cpp | 7 +- .../tests/unittests/TestableSurfaceFlinger.h | 2 +- 6 files changed, 54 insertions(+), 42 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 8de43e0fe6..82c91e7d30 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -223,7 +223,7 @@ std::optional BufferLayer::prepareCli * of a camera where the buffer remains in native orientation, * we want the pixels to always be upright. */ - sp p = mDrawingParent.promote(); + auto p = mDrawingParent; if (p != nullptr) { const auto parentTransform = p->getTransform(); tr = tr * inverseOrientation(parentTransform.getOrientation()); diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 4eeaba154f..ba193c3be2 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -989,7 +989,7 @@ void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) { * how to go from screen space back to window space. */ ui::Transform BufferStateLayer::getInputTransform() const { - sp parent = mDrawingParent.promote(); + auto parent = mDrawingParent; if (parent == nullptr) { return ui::Transform(); } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 4f4a897084..5707c67a56 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -179,9 +179,23 @@ Layer::~Layer() { if (mDrawingState.sidebandStream != nullptr) { mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount(); } + if (mHadClonedChild) { mFlinger->mNumClones--; } + + for (auto const& child : mCurrentChildren) { + if (child->mCurrentParent == this) child->mCurrentParent = nullptr; + if (child->mDrawingParent == this) { + child->mDrawingParent = nullptr; + } + } + for (auto const& child : mDrawingChildren) { + if (child->mCurrentParent == this) child->mCurrentParent = nullptr; + if (child->mDrawingParent == this) { + child->mDrawingParent = nullptr; + } + } } LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp client, std::string name, @@ -237,7 +251,7 @@ void Layer::removeFromCurrentState() { } sp Layer::getRootLayer() { - sp parent = getParent(); + auto parent = getParent(); if (parent == nullptr) { return this; } @@ -662,7 +676,7 @@ bool Layer::isSecure() const { return true; } - const auto p = mDrawingParent.promote(); + const auto p = mDrawingParent; return (p != nullptr) ? p->isSecure() : false; } @@ -845,7 +859,7 @@ bool Layer::isTrustedOverlay() const { if (getDrawingState().isTrustedOverlay) { return true; } - const auto& p = mDrawingParent.promote(); + const auto p = mDrawingParent; return (p != nullptr) && p->isTrustedOverlay(); } @@ -1025,7 +1039,7 @@ int32_t Layer::getFrameRateSelectionPriority() const { return mDrawingState.frameRateSelectionPriority; } // If not, search whether its parents have it set. - sp parent = getParent(); + auto parent = getParent(); if (parent != nullptr) { return parent->getFrameRateSelectionPriority(); } @@ -1038,10 +1052,11 @@ bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) { }; ui::LayerStack Layer::getLayerStack() const { - if (const auto parent = mDrawingParent.promote()) { - return parent->getLayerStack(); + auto p = mDrawingParent; + if (p == nullptr) { + return getDrawingState().layerStack; } - return getDrawingState().layerStack; + return mDrawingParent->getLayerStack(); } bool Layer::setShadowRadius(float shadowRadius) { @@ -1086,7 +1101,7 @@ StretchEffect Layer::getStretchEffect() const { return mDrawingState.stretchEffect; } - sp parent = getParent(); + auto parent = mDrawingParent; if (parent != nullptr) { auto effect = parent->getStretchEffect(); if (effect.hasEffect()) { @@ -1301,7 +1316,7 @@ Layer::FrameRate Layer::getFrameRateForLayerTree() const { bool Layer::isHiddenByPolicy() const { const State& s(mDrawingState); - const auto& parent = mDrawingParent.promote(); + auto parent = mDrawingParent; if (parent != nullptr && parent->isHiddenByPolicy()) { return true; } @@ -1348,7 +1363,7 @@ LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const { LayerDebugInfo info; const State& ds = getDrawingState(); info.mName = getName(); - sp parent = mDrawingParent.promote(); + auto parent = mDrawingParent; info.mParentName = parent ? parent->getName() : "none"s; info.mType = getType(); info.mTransparentRegion = ds.activeTransparentRegion_legacy; @@ -1580,7 +1595,7 @@ ssize_t Layer::removeChild(const sp& layer) { void Layer::setChildrenDrawingParent(const sp& newParent) { for (const sp& child : mDrawingChildren) { - child->mDrawingParent = newParent; + child->mDrawingParent = newParent.get(); child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform, newParent->mEffectiveShadowRadius); } @@ -1600,7 +1615,7 @@ bool Layer::reparent(const sp& newParentHandle) { } } - sp parent = getParent(); + auto parent = getParent(); if (parent != nullptr) { parent->removeChild(this); } @@ -1635,7 +1650,7 @@ bool Layer::setColorTransform(const mat4& matrix) { mat4 Layer::getColorTransform() const { mat4 colorTransform = mat4(getDrawingState().colorTransform); - if (sp parent = mDrawingParent.promote(); parent != nullptr) { + if (auto parent = mDrawingParent; parent != nullptr) { colorTransform = parent->getColorTransform() * colorTransform; } return colorTransform; @@ -1643,7 +1658,7 @@ mat4 Layer::getColorTransform() const { bool Layer::hasColorTransform() const { bool hasColorTransform = getDrawingState().hasColorTransform; - if (sp parent = mDrawingParent.promote(); parent != nullptr) { + if (auto parent = mDrawingParent; parent != nullptr) { hasColorTransform = hasColorTransform || parent->hasColorTransform(); } return hasColorTransform; @@ -1657,7 +1672,7 @@ bool Layer::isLegacyDataSpace() const { } void Layer::setParent(const sp& layer) { - mCurrentParent = layer; + mCurrentParent = layer.get(); } int32_t Layer::getZ(LayerVector::StateSet) const { @@ -1861,7 +1876,7 @@ ui::Transform Layer::getTransform() const { } half Layer::getAlpha() const { - const auto& p = mDrawingParent.promote(); + auto p = mDrawingParent; half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf; return parentAlpha * getDrawingState().color.a; @@ -1872,7 +1887,7 @@ ui::Transform::RotationFlags Layer::getFixedTransformHint() const { if (fixedTransformHint != ui::Transform::ROT_INVALID) { return fixedTransformHint; } - const auto& p = mCurrentParent.promote(); + auto p = mCurrentParent; if (!p) return fixedTransformHint; return p->getFixedTransformHint(); } @@ -1883,7 +1898,7 @@ half4 Layer::getColor() const { } int32_t Layer::getBackgroundBlurRadius() const { - const auto& p = mDrawingParent.promote(); + auto p = mDrawingParent; half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf; return parentAlpha * getDrawingState().backgroundBlurRadius; @@ -1901,9 +1916,8 @@ const std::vector Layer::getBlurRegions() const { Layer::RoundedCornerState Layer::getRoundedCornerState() const { // Get parent settings RoundedCornerState parentSettings; - const auto& parent = mDrawingParent.promote(); - if (parent != nullptr) { - parentSettings = parent->getRoundedCornerState(); + if (mDrawingParent != nullptr) { + parentSettings = mDrawingParent->getRoundedCornerState(); if (parentSettings.radius > 0) { ui::Transform t = getActiveTransform(getDrawingState()); t = t.inverse(); @@ -2119,7 +2133,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet LayerProtoHelper::writeToProtoDeprecated(requestedTransform, layerInfo->mutable_requested_transform()); - auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote(); + auto parent = useDrawing ? mDrawingParent : mCurrentParent; if (parent != nullptr) { layerInfo->set_parent(parent->sequence); } else { @@ -2266,9 +2280,9 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTra } void Layer::fillTouchOcclusionMode(WindowInfo& info) { - sp p = this; + Layer* p = this; while (p != nullptr && !p->hasInputInfo()) { - p = p->mDrawingParent.promote(); + p = p->mDrawingParent; } if (p != nullptr) { info.touchOcclusionMode = p->mDrawingState.inputInfo.touchOcclusionMode; @@ -2280,9 +2294,8 @@ gui::DropInputMode Layer::getDropInputMode() const { if (mode == gui::DropInputMode::ALL) { return mode; } - sp parent = mDrawingParent.promote(); - if (parent) { - gui::DropInputMode parentMode = parent->getDropInputMode(); + if (mDrawingParent) { + gui::DropInputMode parentMode = mDrawingParent->getDropInputMode(); if (parentMode != gui::DropInputMode::NONE) { return parentMode; } @@ -2309,8 +2322,7 @@ void Layer::handleDropInputMode(gui::WindowInfo& info) const { } // Check if the parent has set an alpha on the layer - sp parent = mDrawingParent.promote(); - if (parent && parent->getAlpha() != 1.0_hf) { + if (mDrawingParent && mDrawingParent->getAlpha() != 1.0_hf) { info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(), static_cast(getAlpha())); @@ -2408,10 +2420,10 @@ sp Layer::getClonedRoot() { if (mClonedChild != nullptr) { return this; } - if (mDrawingParent == nullptr || mDrawingParent.promote() == nullptr) { + if (mDrawingParent == nullptr) { return nullptr; } - return mDrawingParent.promote()->getClonedRoot(); + return mDrawingParent->getClonedRoot(); } bool Layer::hasInputInfo() const { @@ -2598,8 +2610,7 @@ bool Layer::isInternalDisplayOverlay() const { return true; } - sp parent = mDrawingParent.promote(); - return parent && parent->isInternalDisplayOverlay(); + return mDrawingParent && mDrawingParent->isInternalDisplayOverlay(); } void Layer::setClonedChild(const sp& clonedChild) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 8209c51ecb..07b2eb5130 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -795,12 +795,12 @@ public: // Returns index if removed, or negative value otherwise // for symmetry with Vector::remove ssize_t removeChild(const sp& layer); - sp getParent() const { return mCurrentParent.promote(); } // Should be called with the surfaceflinger statelock held bool isAtRoot() const { return mIsAtRoot; } void setIsAtRoot(bool isAtRoot) { mIsAtRoot = isAtRoot; } + Layer* getParent() const { return mCurrentParent; } bool hasParent() const { return getParent() != nullptr; } Rect getScreenBounds(bool reduceTransparentRegion = true) const; bool setChildLayer(const sp& childLayer, int32_t z); @@ -1007,8 +1007,8 @@ protected: LayerVector mCurrentChildren{LayerVector::StateSet::Current}; LayerVector mDrawingChildren{LayerVector::StateSet::Drawing}; - wp mCurrentParent; - wp mDrawingParent; + Layer* mCurrentParent = nullptr; + Layer* mDrawingParent = nullptr; // Window types from WindowManager.LayoutParams const gui::WindowInfo::Type mWindowType; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 81f20edca1..acb81dc41c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3412,6 +3412,7 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, const spupdateTransformHint(mActiveDisplayTransformHint); + if (outTransformHint) { *outTransformHint = mActiveDisplayTransformHint; } @@ -3956,7 +3957,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( } if (what & layer_state_t::eLayerChanged) { // NOTE: index needs to be calculated before we update the state - const auto& p = layer->getParent(); + auto p = layer->getParent(); if (p == nullptr) { ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); if (layer->setLayer(s.z) && idx >= 0) { @@ -3974,7 +3975,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( } if (what & layer_state_t::eRelativeLayerChanged) { // NOTE: index needs to be calculated before we update the state - const auto& p = layer->getParent(); + auto p = layer->getParent(); const auto& relativeHandle = s.relativeLayerSurfaceControl ? s.relativeLayerSurfaceControl->getHandle() : nullptr; if (p == nullptr) { @@ -6125,7 +6126,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, return; } - sp p = layer; + auto p = layer; while (p != nullptr) { if (excludeLayers.count(p) != 0) { return; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 7072439cea..db3b5722ec 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -289,7 +289,7 @@ public: } static void setLayerDrawingParent(const sp& layer, const sp& drawingParent) { - layer->mDrawingParent = drawingParent; + layer->mDrawingParent = drawingParent.get(); } /* ------------------------------------------------------------------------ -- cgit v1.2.3-59-g8ed1b From 403a05bc88c5aa6671adcf4214c2a531f77ac2a4 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Fri, 20 Aug 2021 16:28:35 -0700 Subject: Second Patch for async RenderEngine - pass a vector of instead of a vector of pointers to drawLayers function to ensure lifecycle safety. - capture all local variables to call drawLayerInternals in the render engine thread to avoid of pointers being invalidated if it takes long time to pop mFunctions calls. - change renderScreenImplLocked return type as a shared_future object to unblock SF main thread for screen capture events. - block region sampling thread only when SF main thread hasn't completed capture screen event. Bug: 180657548 Test: SurfaceFlinger_test, android.hardware.graphics.composer@2.2-vts, libcompositionengine_test, librenderengine_test, libsurfaceflinger_unittest pass Change-Id: I615f2927d30524988fb12df22fe331e7217c3058 --- libs/renderengine/RenderEngine.cpp | 2 +- libs/renderengine/gl/GLESRenderEngine.cpp | 66 +++++------ libs/renderengine/gl/GLESRenderEngine.h | 2 +- .../include/renderengine/RenderEngine.h | 4 +- .../include/renderengine/mock/RenderEngine.h | 4 +- libs/renderengine/skia/Cache.cpp | 16 +-- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 113 +++++++++--------- libs/renderengine/skia/SkiaGLRenderEngine.h | 7 +- libs/renderengine/skia/SkiaRenderEngine.h | 2 +- libs/renderengine/tests/RenderEngineTest.cpp | 125 +++++++++---------- .../tests/RenderEngineThreadedTest.cpp | 7 +- .../renderengine/threaded/RenderEngineThreaded.cpp | 11 +- libs/renderengine/threaded/RenderEngineThreaded.h | 4 +- services/surfaceflinger/BufferQueueLayer.cpp | 4 +- services/surfaceflinger/BufferQueueLayer.h | 3 +- services/surfaceflinger/BufferStateLayer.cpp | 88 +++----------- services/surfaceflinger/BufferStateLayer.h | 8 +- .../include/compositionengine/LayerFE.h | 4 +- .../include/compositionengine/mock/LayerFE.h | 2 +- .../CompositionEngine/src/Output.cpp | 23 ++-- .../CompositionEngine/src/planner/CachedSet.cpp | 17 +-- .../CompositionEngine/tests/OutputTest.cpp | 87 +++++++++----- .../tests/planner/CachedSetTest.cpp | 84 ++++++------- services/surfaceflinger/Layer.cpp | 3 +- services/surfaceflinger/Layer.h | 3 +- services/surfaceflinger/RegionSamplingThread.cpp | 11 +- services/surfaceflinger/SurfaceFlinger.cpp | 132 +++++++++++++-------- services/surfaceflinger/SurfaceFlinger.h | 22 ++-- .../surfaceflinger/TransactionCallbackInvoker.cpp | 32 +++++ .../surfaceflinger/TransactionCallbackInvoker.h | 6 +- .../tests/unittests/CompositionTest.cpp | 78 ++++++------ 31 files changed, 513 insertions(+), 457 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index 2174df5515..a9ea690a7c 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -96,7 +96,7 @@ void RenderEngine::validateOutputBufferUsage(const sp& buffer) { } std::future RenderEngine::drawLayers( - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { const auto resultPromise = std::make_shared>(); diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 2375cb7bf1..22dd86698b 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -1080,7 +1080,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer void GLESRenderEngine::drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { ATRACE_CALL(); @@ -1110,10 +1110,10 @@ void GLESRenderEngine::drawLayersInternal( std::unique_ptr fbo; // Gathering layers that requested blur, we'll need them to decide when to render to an // offscreen buffer, and when to render to the native buffer. - std::deque blurLayers; + std::deque blurLayers; if (CC_LIKELY(mBlurFilter != nullptr)) { - for (auto layer : layers) { - if (layer->backgroundBlurRadius > 0) { + for (const auto& layer : layers) { + if (layer.backgroundBlurRadius > 0) { blurLayers.push_back(layer); } } @@ -1137,7 +1137,7 @@ void GLESRenderEngine::drawLayersInternal( } else { setViewportAndProjection(display.physicalDisplay, display.clip); auto status = - mBlurFilter->setAsDrawTarget(display, blurLayers.front()->backgroundBlurRadius); + 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); @@ -1167,7 +1167,7 @@ void GLESRenderEngine::drawLayersInternal( .setTexCoords(2 /* size */) .setCropCoords(2 /* size */) .build(); - for (auto const layer : layers) { + for (const auto& layer : layers) { if (blurLayers.size() > 0 && blurLayers.front() == layer) { blurLayers.pop_front(); @@ -1193,7 +1193,7 @@ void GLESRenderEngine::drawLayersInternal( // There's still something else to blur, so let's keep rendering to our FBO // instead of to the display. status = mBlurFilter->setAsDrawTarget(display, - blurLayers.front()->backgroundBlurRadius); + blurLayers.front().backgroundBlurRadius); } if (status != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", @@ -1214,42 +1214,42 @@ void GLESRenderEngine::drawLayersInternal( } // Ensure luminance is at least 100 nits to avoid div-by-zero - const float maxLuminance = std::max(100.f, layer->source.buffer.maxLuminanceNits); + const float maxLuminance = std::max(100.f, layer.source.buffer.maxLuminanceNits); mState.maxMasteringLuminance = maxLuminance; mState.maxContentLuminance = maxLuminance; - mState.projectionMatrix = projectionMatrix * layer->geometry.positionTransform; + mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform; - const FloatRect bounds = layer->geometry.boundaries; + const FloatRect bounds = layer.geometry.boundaries; Mesh::VertexArray position(mesh.getPositionArray()); position[0] = vec2(bounds.left, bounds.top); position[1] = vec2(bounds.left, bounds.bottom); position[2] = vec2(bounds.right, bounds.bottom); position[3] = vec2(bounds.right, bounds.top); - setupLayerCropping(*layer, mesh); - setColorTransform(layer->colorTransform); + setupLayerCropping(layer, mesh); + setColorTransform(layer.colorTransform); bool usePremultipliedAlpha = true; bool disableTexture = true; bool isOpaque = false; - if (layer->source.buffer.buffer != nullptr) { + if (layer.source.buffer.buffer != nullptr) { disableTexture = false; - isOpaque = layer->source.buffer.isOpaque; + isOpaque = layer.source.buffer.isOpaque; - sp gBuf = layer->source.buffer.buffer->getBuffer(); + sp gBuf = layer.source.buffer.buffer->getBuffer(); validateInputBufferUsage(gBuf); - bindExternalTextureBuffer(layer->source.buffer.textureName, gBuf, - layer->source.buffer.fence); + bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf, + layer.source.buffer.fence); - usePremultipliedAlpha = layer->source.buffer.usePremultipliedAlpha; - Texture texture(Texture::TEXTURE_EXTERNAL, layer->source.buffer.textureName); - mat4 texMatrix = layer->source.buffer.textureTransform; + usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha; + Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName); + mat4 texMatrix = layer.source.buffer.textureTransform; texture.setMatrix(texMatrix.asArray()); - texture.setFiltering(layer->source.buffer.useTextureFiltering); + texture.setFiltering(layer.source.buffer.useTextureFiltering); texture.setDimensions(gBuf->getWidth(), gBuf->getHeight()); - setSourceY410BT2020(layer->source.buffer.isY410BT2020); + setSourceY410BT2020(layer.source.buffer.isY410BT2020); renderengine::Mesh::VertexArray texCoords(mesh.getTexCoordArray()); texCoords[0] = vec2(0.0, 0.0); @@ -1264,32 +1264,32 @@ void GLESRenderEngine::drawLayersInternal( } } - const half3 solidColor = layer->source.solidColor; - const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer->alpha); + const half3 solidColor = layer.source.solidColor; + const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha); // Buffer sources will have a black solid color ignored in the shader, // so in that scenario the solid color passed here is arbitrary. setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, - layer->geometry.roundedCornersRadius); - if (layer->disableBlending) { + layer.geometry.roundedCornersRadius); + if (layer.disableBlending) { glDisable(GL_BLEND); } - setSourceDataSpace(layer->sourceDataspace); + setSourceDataSpace(layer.sourceDataspace); - if (layer->shadow.length > 0.0f) { - handleShadow(layer->geometry.boundaries, layer->geometry.roundedCornersRadius, - layer->shadow); + if (layer.shadow.length > 0.0f) { + handleShadow(layer.geometry.boundaries, layer.geometry.roundedCornersRadius, + layer.shadow); } // We only want to do a special handling for rounded corners when having rounded corners // is the only reason it needs to turn on blending, otherwise, we handle it like the // usual way since it needs to turn on blending anyway. - else if (layer->geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) { - handleRoundedCorners(display, *layer, mesh); + else if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) { + handleRoundedCorners(display, layer, mesh); } else { drawMesh(mesh); } // Cleanup if there's a buffer source - if (layer->source.buffer.buffer != nullptr) { + if (layer.source.buffer.buffer != nullptr) { disableBlending(); setSourceY410BT2020(false); disableTexturing(); diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index c4adfdf752..1d7c2cafb5 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -104,7 +104,7 @@ protected: bool canSkipPostRenderCleanup() const override; void drawLayersInternal(const std::shared_ptr>&& resultPromise, const DisplaySettings& display, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 701c1f2071..b9cc6485e5 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -160,7 +160,7 @@ public: // @return A future object of RenderEngineResult struct indicating whether // drawing was successful in async mode. virtual std::future drawLayers( - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence); @@ -231,7 +231,7 @@ protected: virtual void drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) = 0; }; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index a7e6809223..248bd652c0 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -49,12 +49,12 @@ public: MOCK_CONST_METHOD0(canSkipPostRenderCleanup, bool()); MOCK_METHOD5(drawLayers, std::future(const DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, base::unique_fd&&)); MOCK_METHOD6(drawLayersInternal, void(const std::shared_ptr>&&, - const DisplaySettings&, const std::vector&, + const DisplaySettings&, const std::vector&, const std::shared_ptr&, const bool, base::unique_fd&&)); MOCK_METHOD0(cleanFramebufferCache, void()); MOCK_METHOD0(getContextPriority, int()); diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index c4fa1bb091..b18a872836 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -95,7 +95,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin .alpha = 1, }; - auto layers = std::vector{&layer, &caster}; + auto layers = std::vector{layer, caster}; // Four combinations of settings are used (two transforms here, and drawShadowLayers is // called with two different destination data spaces) They're all rounded rect. // Three of these are cache misses that generate new shaders. @@ -140,7 +140,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting }}, }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) { layer.sourceDataspace = dataspace; // Cache shaders for both rects and round rects. @@ -176,7 +176,7 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting .alpha = 0.5, }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; for (auto transform : {mat4(), kScaleAndTranslate}) { layer.geometry.positionTransform = transform; for (float roundedCornersRadius : {0.0f, 50.f}) { @@ -201,7 +201,7 @@ static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings .skipContentDraw = true, }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; // Different blur code is invoked for radii less and greater than 30 pixels for (int radius : {9, 60}) { layer.backgroundBlurRadius = radius; @@ -242,7 +242,7 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti }, }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) { layer.source = pixelSource; for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) { @@ -289,7 +289,7 @@ static void drawPIPImageLayer(SkiaRenderEngine* renderengine, const DisplaySetti }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd()); } @@ -317,7 +317,7 @@ static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySett }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd()); } @@ -429,7 +429,7 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { LayerSettings layer{ .source = PixelSource{.solidColor = half3(0.f, 0.f, 0.f)}, }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; // call get() to make it synchronous renderengine ->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd()) diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index cb686a643a..d5ec774e9c 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -610,17 +610,18 @@ private: AutoBackendTexture::CleanupManager& mMgr; }; -sk_sp SkiaGLRenderEngine::createRuntimeEffectShader( - sk_sp shader, - const LayerSettings* layer, const DisplaySettings& display, bool undoPremultipliedAlpha, - bool requiresLinearEffect) { - const auto stretchEffect = layer->stretchEffect; +sk_sp SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp shader, + const LayerSettings& layer, + const DisplaySettings& display, + bool undoPremultipliedAlpha, + bool requiresLinearEffect) { + const auto stretchEffect = layer.stretchEffect; // The given surface will be stretched by HWUI via matrix transformation // which gets similar results for most surfaces // Determine later on if we need to leverage the stertch shader within // surface flinger if (stretchEffect.hasEffect()) { - const auto targetBuffer = layer->source.buffer.buffer; + const auto targetBuffer = layer.source.buffer.buffer; const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr; if (graphicBuffer && shader) { shader = mStretchShaderFactory.createSkShader(shader, stretchEffect); @@ -629,7 +630,7 @@ sk_sp SkiaGLRenderEngine::createRuntimeEffectShader( if (requiresLinearEffect) { const ui::Dataspace inputDataspace = - mUseColorManagement ? layer->sourceDataspace : ui::Dataspace::V0_SRGB_LINEAR; + mUseColorManagement ? layer.sourceDataspace : ui::Dataspace::V0_SRGB_LINEAR; const ui::Dataspace outputDataspace = mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR; @@ -645,13 +646,13 @@ sk_sp SkiaGLRenderEngine::createRuntimeEffectShader( } else { runtimeEffect = effectIter->second; } - float maxLuminance = layer->source.buffer.maxLuminanceNits; + 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, + return createLinearEffectShader(shader, effect, runtimeEffect, layer.colorTransform, display.maxLuminance, maxLuminance); } return shader; @@ -729,7 +730,7 @@ static SkRRect getBlurRRect(const BlurRegion& region) { void SkiaGLRenderEngine::drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool /*useFramebufferCache*/, base::unique_fd&& bufferFence) { ATRACE_NAME("SkiaGL::drawLayers"); @@ -801,11 +802,11 @@ void SkiaGLRenderEngine::drawLayersInternal( if (!layerHasBlur(layer, ctModifiesAlpha)) { continue; } - if (layer->backgroundBlurRadius > 0 && - layer->backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) { + if (layer.backgroundBlurRadius > 0 && + layer.backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) { requiresCompositionLayer = true; } - for (auto region : layer->blurRegions) { + for (auto region : layer.blurRegions) { if (region.blurRadius < BlurFilter::kMaxCrossFadeRadius) { requiresCompositionLayer = true; } @@ -813,7 +814,7 @@ void SkiaGLRenderEngine::drawLayersInternal( if (requiresCompositionLayer) { activeSurface = dstSurface->makeSurface(dstSurface->imageInfo()); canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState); - blurCompositionLayer = layer; + blurCompositionLayer = &layer; break; } } @@ -825,11 +826,11 @@ void SkiaGLRenderEngine::drawLayersInternal( initCanvas(canvas, display); for (const auto& layer : layers) { - ATRACE_FORMAT("DrawLayer: %s", layer->name.c_str()); + ATRACE_FORMAT("DrawLayer: %s", layer.name.c_str()); if (kPrintLayerSettings) { std::stringstream ls; - PrintTo(*layer, &ls); + PrintTo(layer, &ls); auto debugs = ls.str(); int pos = 0; while (pos < debugs.size()) { @@ -839,7 +840,7 @@ void SkiaGLRenderEngine::drawLayersInternal( } sk_sp blurInput; - if (blurCompositionLayer == layer) { + if (blurCompositionLayer == &layer) { LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface); LOG_ALWAYS_FATAL_IF(canvas == dstCanvas); @@ -878,17 +879,17 @@ void SkiaGLRenderEngine::drawLayersInternal( if (CC_UNLIKELY(mCapture->isCaptureRunning())) { // Record the name of the layer if the capture is running. std::stringstream layerSettings; - PrintTo(*layer, &layerSettings); + PrintTo(layer, &layerSettings); // Store the LayerSettings in additional information. - canvas->drawAnnotation(SkRect::MakeEmpty(), layer->name.c_str(), + canvas->drawAnnotation(SkRect::MakeEmpty(), layer.name.c_str(), SkData::MakeWithCString(layerSettings.str().c_str())); } // Layers have a local transform that should be applied to them - canvas->concat(getSkM44(layer->geometry.positionTransform).asM33()); + canvas->concat(getSkM44(layer.geometry.positionTransform).asM33()); const auto [bounds, roundRectClip] = - getBoundsAndClip(layer->geometry.boundaries, layer->geometry.roundedCornersCrop, - layer->geometry.roundedCornersRadius); + getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop, + layer.geometry.roundedCornersRadius); if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) { std::unordered_map> cachedBlurs; @@ -909,20 +910,19 @@ void SkiaGLRenderEngine::drawLayersInternal( // TODO(b/182216890): Filter out empty layers earlier if (blurRect.width() > 0 && blurRect.height() > 0) { - if (layer->backgroundBlurRadius > 0) { + if (layer.backgroundBlurRadius > 0) { ATRACE_NAME("BackgroundBlur"); - auto blurredImage = - mBlurFilter->generate(grContext, layer->backgroundBlurRadius, blurInput, - blurRect); + auto blurredImage = mBlurFilter->generate(grContext, layer.backgroundBlurRadius, + blurInput, blurRect); - cachedBlurs[layer->backgroundBlurRadius] = blurredImage; + cachedBlurs[layer.backgroundBlurRadius] = blurredImage; - mBlurFilter->drawBlurRegion(canvas, bounds, layer->backgroundBlurRadius, 1.0f, + mBlurFilter->drawBlurRegion(canvas, bounds, layer.backgroundBlurRadius, 1.0f, blurRect, blurredImage, blurInput); } - canvas->concat(getSkM44(layer->blurRegionTransform).asM33()); - for (auto region : layer->blurRegions) { + canvas->concat(getSkM44(layer.blurRegionTransform).asM33()); + for (auto region : layer.blurRegions) { if (cachedBlurs[region.blurRadius] == nullptr) { ATRACE_NAME("BlurRegion"); cachedBlurs[region.blurRadius] = @@ -937,19 +937,18 @@ void SkiaGLRenderEngine::drawLayersInternal( } } - if (layer->shadow.length > 0) { + if (layer.shadow.length > 0) { // This would require a new parameter/flag to SkShadowUtils::DrawShadow - LOG_ALWAYS_FATAL_IF(layer->disableBlending, "Cannot disableBlending with a shadow"); + LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow"); SkRRect shadowBounds, shadowClip; - if (layer->geometry.boundaries == layer->shadow.boundaries) { + if (layer.geometry.boundaries == layer.shadow.boundaries) { shadowBounds = bounds; shadowClip = roundRectClip; } else { std::tie(shadowBounds, shadowClip) = - getBoundsAndClip(layer->shadow.boundaries, - layer->geometry.roundedCornersCrop, - layer->geometry.roundedCornersRadius); + getBoundsAndClip(layer.shadow.boundaries, layer.geometry.roundedCornersCrop, + layer.geometry.roundedCornersRadius); } // Technically, if bounds is a rect and roundRectClip is not empty, @@ -960,18 +959,18 @@ void SkiaGLRenderEngine::drawLayersInternal( // looks more like the intent. const auto& rrect = shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds; - drawShadow(canvas, rrect, layer->shadow); + drawShadow(canvas, rrect, layer.shadow); } - const bool requiresLinearEffect = layer->colorTransform != mat4() || + 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->skipContentDraw || - (layer->alpha == 0 && !requiresLinearEffect && !layer->disableBlending && + if (layer.skipContentDraw || + (layer.alpha == 0 && !requiresLinearEffect && !layer.disableBlending && (!displayColorTransform || displayColorTransform->isAlphaUnchanged()))) { continue; } @@ -981,13 +980,13 @@ void SkiaGLRenderEngine::drawLayersInternal( // management is a no-op. const ui::Dataspace layerDataspace = (!mUseColorManagement || requiresLinearEffect) ? dstDataspace - : layer->sourceDataspace; + : layer.sourceDataspace; SkPaint paint; - if (layer->source.buffer.buffer) { + if (layer.source.buffer.buffer) { ATRACE_NAME("DrawImage"); - validateInputBufferUsage(layer->source.buffer.buffer->getBuffer()); - const auto& item = layer->source.buffer; + validateInputBufferUsage(layer.source.buffer.buffer->getBuffer()); + const auto& item = layer.source.buffer; std::shared_ptr imageTextureRef = nullptr; if (const auto& iter = cache.find(item.buffer->getBuffer()->getId()); @@ -1006,8 +1005,8 @@ void SkiaGLRenderEngine::drawLayersInternal( // if the layer's buffer has a fence, then we must must respect the fence prior to using // the buffer. - if (layer->source.buffer.fence != nullptr) { - waitFence(layer->source.buffer.fence->get()); + if (layer.source.buffer.fence != nullptr) { + waitFence(layer.source.buffer.fence->get()); } // isOpaque means we need to ignore the alpha in the image, @@ -1051,7 +1050,7 @@ void SkiaGLRenderEngine::drawLayersInternal( sk_sp shader; - if (layer->source.buffer.useTextureFiltering) { + if (layer.source.buffer.useTextureFiltering) { shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions( {SkFilterMode::kLinear, SkMipmapMode::kNone}), @@ -1069,21 +1068,21 @@ void SkiaGLRenderEngine::drawLayersInternal( paint.setShader(createRuntimeEffectShader(shader, layer, display, !item.isOpaque && item.usePremultipliedAlpha, requiresLinearEffect)); - paint.setAlphaf(layer->alpha); + paint.setAlphaf(layer.alpha); } else { ATRACE_NAME("DrawColor"); - const auto color = layer->source.solidColor; + const auto color = layer.source.solidColor; sk_sp shader = SkShaders::Color(SkColor4f{.fR = color.r, .fG = color.g, .fB = color.b, - .fA = layer->alpha}, + .fA = layer.alpha}, toSkColorSpace(layerDataspace)); paint.setShader(createRuntimeEffectShader(shader, layer, display, /* undoPremultipliedAlpha */ false, requiresLinearEffect)); } - if (layer->disableBlending) { + if (layer.disableBlending) { paint.setBlendMode(SkBlendMode::kSrc); } @@ -1251,13 +1250,13 @@ inline std::pair SkiaGLRenderEngine::getBoundsAndClip(const Fl return {SkRRect::MakeRect(bounds), clip}; } -inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings* layer, +inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings& layer, bool colorTransformModifiesAlpha) { - if (layer->backgroundBlurRadius > 0 || layer->blurRegions.size()) { + if (layer.backgroundBlurRadius > 0 || layer.blurRegions.size()) { // return false if the content is opaque and would therefore occlude the blur - const bool opaqueContent = !layer->source.buffer.buffer || layer->source.buffer.isOpaque; - const bool opaqueAlpha = layer->alpha == 1.0f && !colorTransformModifiesAlpha; - return layer->skipContentDraw || !(opaqueContent && opaqueAlpha); + const bool opaqueContent = !layer.source.buffer.buffer || layer.source.buffer.isOpaque; + const bool opaqueAlpha = layer.alpha == 1.0f && !colorTransformModifiesAlpha; + return layer.skipContentDraw || !(opaqueContent && opaqueAlpha); } return false; } diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index e010c35c13..74ce6513e9 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -74,7 +74,7 @@ protected: bool canSkipPostRenderCleanup() const override; void drawLayersInternal(const std::shared_ptr>&& resultPromise, const DisplaySettings& display, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override; @@ -92,7 +92,7 @@ private: inline SkRect getSkRect(const Rect& layer); inline std::pair getBoundsAndClip(const FloatRect& bounds, const FloatRect& crop, float cornerRadius); - inline bool layerHasBlur(const LayerSettings* layer, bool colorTransformModifiesAlpha); + inline bool layerHasBlur(const LayerSettings& layer, bool colorTransformModifiesAlpha); inline SkColor getSkColor(const vec4& color); inline SkM44 getSkM44(const mat4& matrix); inline SkPoint3 getSkPoint3(const vec3& vector); @@ -108,8 +108,7 @@ private: const ShadowSettings& shadowSettings); // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned. // Otherwise it returns the input shader. - sk_sp createRuntimeEffectShader(sk_sp shader, - const LayerSettings* layer, + sk_sp createRuntimeEffectShader(sk_sp shader, const LayerSettings& layer, const DisplaySettings& display, bool undoPremultipliedAlpha, bool requiresLinearEffect); diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index f61653b940..eb65e83324 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -55,7 +55,7 @@ protected: virtual void drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override { resultPromise->set_value({NO_ERROR, base::unique_fd()}); diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 694bda65d4..c2c05f41b7 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -417,10 +417,11 @@ public: DEFAULT_DISPLAY_HEIGHT - DEFAULT_DISPLAY_OFFSET); } - void invokeDraw(renderengine::DisplaySettings settings, - std::vector layers) { + void invokeDraw(const renderengine::DisplaySettings& settings, + const std::vector& layers) { std::future result = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd()); + ASSERT_TRUE(result.valid()); auto [status, fence] = result.get(); @@ -436,7 +437,7 @@ public: void drawEmptyLayers() { renderengine::DisplaySettings settings; - std::vector layers; + std::vector layers; invokeDraw(settings, layers); } @@ -629,7 +630,7 @@ void RenderEngineTest::fillBuffer(half r, half g, half b, half a) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -637,7 +638,7 @@ void RenderEngineTest::fillBuffer(half r, half g, half b, half a) { SourceVariant::fillColor(layer, r, g, b, this); layer.alpha = a; - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -673,7 +674,7 @@ void RenderEngineTest::fillRedOffsetBuffer() { settings.physicalDisplay = offsetRect(); settings.clip = offsetRectAtZero(); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -681,7 +682,7 @@ void RenderEngineTest::fillRedOffsetBuffer() { SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0f; - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -708,7 +709,7 @@ void RenderEngineTest::fillBufferCheckers(uint32_t orientationFlag) { settings.clip = Rect(2, 2); settings.orientation = orientationFlag; - std::vector layers; + std::vector layers; renderengine::LayerSettings layerOne; layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -731,9 +732,9 @@ void RenderEngineTest::fillBufferCheckers(uint32_t orientationFlag) { SourceVariant::fillColor(layerThree, 0.0f, 0.0f, 1.0f, this); layerThree.alpha = 1.0f; - layers.push_back(&layerOne); - layers.push_back(&layerTwo); - layers.push_back(&layerThree); + layers.push_back(layerOne); + layers.push_back(layerTwo); + layers.push_back(layerThree); invokeDraw(settings, layers); } @@ -810,7 +811,7 @@ void RenderEngineTest::fillBufferWithLayerTransform() { settings.clip = Rect(2, 2); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -821,7 +822,7 @@ void RenderEngineTest::fillBufferWithLayerTransform() { layer.source.solidColor = half3(1.0f, 0.0f, 0.0f); layer.alpha = 1.0f; - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -843,7 +844,7 @@ void RenderEngineTest::fillBufferWithColorTransform() { settings.clip = Rect(1, 1); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -860,7 +861,7 @@ void RenderEngineTest::fillBufferWithColorTransform() { layer.alpha = 1.0f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -877,7 +878,7 @@ void RenderEngineTest::fillBufferWithColorTransformZeroLayerAlpha() { settings.physicalDisplay = fullscreenRect(); settings.clip = Rect(1, 1); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); @@ -890,7 +891,7 @@ void RenderEngineTest::fillBufferWithColorTransformZeroLayerAlpha() { layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -908,7 +909,7 @@ void RenderEngineTest::fillRedBufferWithRoundedCorners() { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -918,7 +919,7 @@ void RenderEngineTest::fillRedBufferWithRoundedCorners() { SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0f; - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -949,14 +950,14 @@ void RenderEngineTest::fillBufferAndBlurBackground() { settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; renderengine::LayerSettings backgroundLayer; backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect(); SourceVariant::fillColor(backgroundLayer, 0.0f, 1.0f, 0.0f, this); backgroundLayer.alpha = 1.0f; - layers.push_back(&backgroundLayer); + layers.emplace_back(backgroundLayer); renderengine::LayerSettings leftLayer; leftLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -964,7 +965,7 @@ void RenderEngineTest::fillBufferAndBlurBackground() { Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT).toFloatRect(); SourceVariant::fillColor(leftLayer, 1.0f, 0.0f, 0.0f, this); leftLayer.alpha = 1.0f; - layers.push_back(&leftLayer); + layers.emplace_back(leftLayer); renderengine::LayerSettings blurLayer; blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -972,7 +973,7 @@ void RenderEngineTest::fillBufferAndBlurBackground() { blurLayer.backgroundBlurRadius = blurRadius; SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this); blurLayer.alpha = 0; - layers.push_back(&blurLayer); + layers.emplace_back(blurLayer); invokeDraw(settings, layers); @@ -994,14 +995,14 @@ void RenderEngineTest::fillSmallLayerAndBlurBackground() { settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; renderengine::LayerSettings backgroundLayer; backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect(); SourceVariant::fillColor(backgroundLayer, 1.0f, 0.0f, 0.0f, this); backgroundLayer.alpha = 1.0f; - layers.push_back(&backgroundLayer); + layers.push_back(backgroundLayer); renderengine::LayerSettings blurLayer; blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1009,7 +1010,7 @@ void RenderEngineTest::fillSmallLayerAndBlurBackground() { blurLayer.backgroundBlurRadius = blurRadius; SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this); blurLayer.alpha = 0; - layers.push_back(&blurLayer); + layers.push_back(blurLayer); invokeDraw(settings, layers); @@ -1026,7 +1027,7 @@ void RenderEngineTest::overlayCorners() { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layersFirst; + std::vector layersFirst; renderengine::LayerSettings layerOne; layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1035,14 +1036,14 @@ void RenderEngineTest::overlayCorners() { SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this); layerOne.alpha = 0.2; - layersFirst.push_back(&layerOne); + layersFirst.push_back(layerOne); invokeDraw(settings, layersFirst); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 0); - std::vector layersSecond; + std::vector layersSecond; renderengine::LayerSettings layerTwo; layerTwo.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; layerTwo.geometry.boundaries = @@ -1051,7 +1052,7 @@ void RenderEngineTest::overlayCorners() { SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this); layerTwo.alpha = 1.0f; - layersSecond.push_back(&layerTwo); + layersSecond.push_back(layerTwo); invokeDraw(settings, layersSecond); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0); @@ -1066,7 +1067,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() { settings.clip = Rect(1, 1); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1102,7 +1103,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() { layer.alpha = 1.0f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -1118,7 +1119,7 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() { // Here logical space is 1x1 settings.clip = Rect(1, 1); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; const auto buf = allocateSourceBuffer(1, 1); @@ -1141,7 +1142,7 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() { layer.alpha = 0.5f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -1157,7 +1158,7 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() { // Here logical space is 1x1 settings.clip = Rect(1, 1); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; const auto buf = allocateSourceBuffer(1, 1); @@ -1180,7 +1181,7 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() { layer.alpha = 0.5f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -1199,7 +1200,7 @@ void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLaye settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; // add background layer renderengine::LayerSettings bgLayer; @@ -1208,7 +1209,7 @@ void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLaye ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f, backgroundColor.b / 255.0f, this); bgLayer.alpha = backgroundColor.a / 255.0f; - layers.push_back(&bgLayer); + layers.push_back(bgLayer); // add shadow layer renderengine::LayerSettings shadowLayer; @@ -1216,14 +1217,14 @@ void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLaye shadowLayer.geometry.boundaries = castingLayer.geometry.boundaries; shadowLayer.alpha = castingLayer.alpha; shadowLayer.shadow = shadow; - layers.push_back(&shadowLayer); + layers.push_back(shadowLayer); // add layer casting the shadow renderengine::LayerSettings layer = castingLayer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; SourceVariant::fillColor(layer, casterColor.r / 255.0f, casterColor.g / 255.0f, casterColor.b / 255.0f, this); - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -1236,7 +1237,7 @@ void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds, settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; // add background layer renderengine::LayerSettings bgLayer; @@ -1245,7 +1246,7 @@ void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds, ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f, backgroundColor.b / 255.0f, this); bgLayer.alpha = backgroundColor.a / 255.0f; - layers.push_back(&bgLayer); + layers.push_back(bgLayer); // add shadow layer renderengine::LayerSettings shadowLayer; @@ -1255,7 +1256,7 @@ void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds, shadowLayer.alpha = 1.0f; ColorSourceVariant::fillColor(shadowLayer, 0, 0, 0, this); shadowLayer.shadow = shadow; - layers.push_back(&shadowLayer); + layers.push_back(shadowLayer); invokeDraw(settings, layers); } @@ -1291,8 +1292,8 @@ TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) { // Transform the red color. bgLayer.colorTransform = mat4(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - std::vector layers; - layers.push_back(&bgLayer); + std::vector layers; + layers.push_back(bgLayer); invokeDraw(settings, layers); @@ -1306,11 +1307,11 @@ TEST_P(RenderEngineTest, drawLayers_nullOutputBuffer) { renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + 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); + layers.push_back(layer); std::future result = mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd()); @@ -1335,12 +1336,12 @@ TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) { settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = fullscreenRect().toFloatRect(); BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0; - layers.push_back(&layer); + layers.push_back(layer); std::future result = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd()); @@ -1743,12 +1744,12 @@ TEST_P(RenderEngineTest, cleanupPostRender_cleansUpOnce) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = fullscreenRect().toFloatRect(); BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0; - layers.push_back(&layer); + layers.push_back(layer); std::future resultOne = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd()); @@ -1779,7 +1780,7 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1790,7 +1791,7 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); redLayer.alpha = 1.0f; - layers.push_back(&redLayer); + layers.push_back(redLayer); // Green layer with 1/3 size. renderengine::LayerSettings greenLayer; @@ -1805,7 +1806,7 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f); greenLayer.alpha = 1.0f; - layers.push_back(&greenLayer); + layers.push_back(greenLayer); invokeDraw(settings, layers); @@ -1828,7 +1829,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1839,7 +1840,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); redLayer.alpha = 1.0f; - layers.push_back(&redLayer); + layers.push_back(redLayer); // Green layer with 1/2 size with parent crop rect. renderengine::LayerSettings greenLayer = redLayer; @@ -1847,7 +1848,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT / 2); greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f); - layers.push_back(&greenLayer); + layers.push_back(greenLayer); invokeDraw(settings, layers); @@ -1873,7 +1874,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1884,7 +1885,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) { redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); redLayer.alpha = 1.0f; - layers.push_back(&redLayer); + layers.push_back(redLayer); invokeDraw(settings, layers); // Due to roundedCornersRadius, the top corners are untouched. @@ -1923,7 +1924,7 @@ TEST_P(RenderEngineTest, testClear) { .disableBlending = true, }; - std::vector layers{&redLayer, &clearLayer}; + std::vector layers{redLayer, clearLayer}; invokeDraw(display, layers); expectBufferColor(rect, 0, 0, 0, 0); } @@ -1971,7 +1972,7 @@ TEST_P(RenderEngineTest, testDisableBlendingBuffer) { .disableBlending = true, }; - std::vector layers{&redLayer, &greenLayer}; + std::vector layers{redLayer, greenLayer}; invokeDraw(display, layers); expectBufferColor(rect, 0, 128, 0, 128); } @@ -2017,7 +2018,7 @@ TEST_P(RenderEngineTest, test_isOpaque) { .alpha = 1.0f, }; - std::vector layers{&greenLayer}; + std::vector layers{greenLayer}; invokeDraw(display, layers); if (GetParam()->useColorManagement()) { diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index 99250c1412..db7e12b71b 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -172,20 +172,21 @@ TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsTrue) { TEST_F(RenderEngineThreadedTest, drawLayers) { renderengine::DisplaySettings settings; - std::vector layers; + std::vector layers; std::shared_ptr buffer = std::make_shared< renderengine::ExternalTexture>(new GraphicBuffer(), *mRenderEngine, renderengine::ExternalTexture::Usage::READABLE | renderengine::ExternalTexture::Usage::WRITEABLE); + base::unique_fd bufferFence; EXPECT_CALL(*mRenderEngine, drawLayersInternal) .WillOnce([&](const std::shared_ptr>&& resultPromise, const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd &&) -> void { + base::unique_fd&&) -> void { resultPromise->set_value({NO_ERROR, base::unique_fd()}); }); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index a549672259..3d446e8e72 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -306,7 +306,7 @@ bool RenderEngineThreaded::canSkipPostRenderCleanup() const { void RenderEngineThreaded::drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { resultPromise->set_value({NO_ERROR, base::unique_fd()}); @@ -314,19 +314,20 @@ void RenderEngineThreaded::drawLayersInternal( } std::future RenderEngineThreaded::drawLayers( - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { ATRACE_CALL(); const auto resultPromise = std::make_shared>(); std::future resultFuture = resultPromise->get_future(); + int fd = bufferFence.release(); { std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([resultPromise, &display, &layers, &buffer, useFramebufferCache, - &bufferFence](renderengine::RenderEngine& instance) { + mFunctionCalls.push([resultPromise, display, layers, buffer, useFramebufferCache, + fd](renderengine::RenderEngine& instance) { ATRACE_NAME("REThreaded::drawLayers"); instance.drawLayersInternal(std::move(resultPromise), display, layers, buffer, - useFramebufferCache, std::move(bufferFence)); + useFramebufferCache, base::unique_fd(fd)); }); } mCondition.notify_one(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 2303caa7eb..0159cfaece 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -57,7 +57,7 @@ public: void cleanupPostRender() override; std::future drawLayers(const DisplaySettings& display, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override; @@ -73,7 +73,7 @@ protected: bool canSkipPostRenderCleanup() const override; void drawLayersInternal(const std::shared_ptr>&& resultPromise, const DisplaySettings& display, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index f98681e1ce..6c60e53841 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -48,7 +48,9 @@ BufferQueueLayer::~BufferQueueLayer() { // Interface implementation for Layer // ----------------------------------------------------------------------- -void BufferQueueLayer::onLayerDisplayed(const sp& releaseFence) { +void BufferQueueLayer::onLayerDisplayed( + std::shared_future futureRenderEngineResult) { + sp releaseFence = new Fence(dup(futureRenderEngineResult.get().drawFence)); mConsumer->setReleaseFence(releaseFence); // Prevent tracing the same release multiple times. diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index a3bd725cfe..dfdb5c055d 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -42,7 +42,8 @@ public: // Implements Layer. const char* getType() const override { return "BufferQueueLayer"; } - void onLayerDisplayed(const sp& releaseFence) override; + void onLayerDisplayed( + std::shared_future futureRenderEngineResult) override; // If a buffer was replaced this frame, release the former buffer void releasePendingBuffer(nsecs_t dequeueReadyTime) override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 132ee9d71b..454363ac3f 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -70,69 +70,11 @@ BufferStateLayer::~BufferStateLayer() { } } -status_t BufferStateLayer::addReleaseFence(const sp& ch, - const sp& fence) { - if (ch == nullptr) { - return OK; - } - ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; - if (!ch->previousReleaseFence.get()) { - ch->previousReleaseFence = fence; - return OK; - } - - // Below logic is lifted from ConsumerBase.cpp: - // Check status of fences first because merging is expensive. - // Merging an invalid fence with any other fence results in an - // invalid fence. - auto currentStatus = ch->previousReleaseFence->getStatus(); - if (currentStatus == Fence::Status::Invalid) { - ALOGE("Existing fence has invalid state, layer: %s", mName.c_str()); - return BAD_VALUE; - } - - auto incomingStatus = fence->getStatus(); - if (incomingStatus == Fence::Status::Invalid) { - ALOGE("New fence has invalid state, layer: %s", mName.c_str()); - ch->previousReleaseFence = fence; - return BAD_VALUE; - } - - // If both fences are signaled or both are unsignaled, we need to merge - // them to get an accurate timestamp. - if (currentStatus == incomingStatus) { - char fenceName[32] = {}; - snprintf(fenceName, 32, "%.28s", mName.c_str()); - sp mergedFence = Fence::merge( - fenceName, ch->previousReleaseFence, fence); - if (!mergedFence.get()) { - ALOGE("failed to merge release fences, layer: %s", mName.c_str()); - // synchronization is broken, the best we can do is hope fences - // signal in order so the new fence will act like a union - ch->previousReleaseFence = fence; - return BAD_VALUE; - } - ch->previousReleaseFence = mergedFence; - } else if (incomingStatus == Fence::Status::Unsignaled) { - // If one fence has signaled and the other hasn't, the unsignaled - // fence will approximately correspond with the correct timestamp. - // There's a small race if both fences signal at about the same time - // and their statuses are retrieved with unfortunate timing. However, - // by this point, they will have both signaled and only the timestamp - // will be slightly off; any dependencies after this point will - // already have been met. - ch->previousReleaseFence = fence; - } - // else if (currentStatus == Fence::Status::Unsignaled) is a no-op. - - return OK; -} - // ----------------------------------------------------------------------- // Interface implementation for Layer // ----------------------------------------------------------------------- -void BufferStateLayer::onLayerDisplayed(const sp& releaseFence) { - +void BufferStateLayer::onLayerDisplayed( + std::shared_future futureRenderEngineResult) { // If a layer has been displayed again we may need to clear // the mLastClientComposition fence that we use for early release in setBuffer // (as we now have a new fence which won't pass through the client composition path in some cases @@ -146,9 +88,6 @@ void BufferStateLayer::onLayerDisplayed(const sp& releaseFence) { mLastClientCompositionDisplayed = true; } - if (!releaseFence->isValid()) { - return; - } // The previous release fence notifies the client that SurfaceFlinger is done with the previous // buffer that was presented on this layer. The first transaction that came in this frame that // replaced the previous buffer on this layer needs this release fence, because the fence will @@ -173,17 +112,19 @@ void BufferStateLayer::onLayerDisplayed(const sp& releaseFence) { break; } } - auto status = addReleaseFence(ch, releaseFence); - if (status != OK) { - ALOGE("Failed to add release fence for layer %s", getName().c_str()); - } - mPreviousReleaseFence = releaseFence; + mListPreviousReleaseFences.emplace_back(futureRenderEngineResult); // Prevent tracing the same release multiple times. if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) { mPreviousReleasedFrameNumber = mPreviousFrameNumber; } + + if (ch != nullptr) { + ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; + ch->previousReleaseFences.emplace_back(futureRenderEngineResult); + ch->name = mName; + } } void BufferStateLayer::onSurfaceFrameCreated( @@ -231,9 +172,18 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { mFlinger->getTransactionCallbackInvoker().addCallbackHandles( mDrawingState.callbackHandles, jankData); + sp releaseFence = Fence::NO_FENCE; + for (auto& handle : mDrawingState.callbackHandles) { + if (handle->releasePreviousBuffer && + mDrawingState.releaseBufferEndpoint == handle->listener) { + releaseFence = + handle->previousReleaseFence ? handle->previousReleaseFence : Fence::NO_FENCE; + break; + } + } + mDrawingState.callbackHandles = {}; - const sp& releaseFence(mPreviousReleaseFence); std::shared_ptr releaseFenceTime = std::make_shared(releaseFence); { Mutex::Autolock lock(mFrameEventHistoryMutex); diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 87b68ea71b..6cb9b352f8 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -39,7 +39,9 @@ public: // Implements Layer. const char* getType() const override { return "BufferStateLayer"; } - void onLayerDisplayed(const sp& releaseFence) override; + void onLayerDisplayed( + std::shared_future futureRenderEngineResult) override; + void releasePendingBuffer(nsecs_t dequeueReadyTime) override; void finalizeFrameEventHistory(const std::shared_ptr& glDoneFence, @@ -115,8 +117,6 @@ private: bool updateFrameEventHistory(const sp& acquireFence, nsecs_t postedTime, nsecs_t requestedPresentTime); - status_t addReleaseFence(const sp& ch, const sp& releaseFence); - bool latchSidebandStream(bool& recomputeVisibleRegions) override; bool hasFrameUpdate() const override; @@ -139,7 +139,7 @@ private: std::shared_ptr getBufferFromBufferData( const BufferData& bufferData); - sp mPreviousReleaseFence; + std::vector> mListPreviousReleaseFences; ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; uint64_t mPreviousReleasedFrameNumber = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index f7b71cf9fe..ac243c0a17 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -26,6 +27,7 @@ #pragma clang diagnostic ignored "-Wextra" #include +#include // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" @@ -151,7 +153,7 @@ public: ClientCompositionTargetSettings&) = 0; // Called after the layer is displayed to update the presentation fence - virtual void onLayerDisplayed(const sp&) = 0; + virtual void onLayerDisplayed(std::shared_future) = 0; // Gets some kind of identifier for the layer for debug purposes. virtual const char* getDebugName() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index d215bda891..16aebef9f3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -39,7 +39,7 @@ public: std::vector( compositionengine::LayerFE::ClientCompositionTargetSettings&)); - MOCK_METHOD1(onLayerDisplayed, void(const sp&)); + MOCK_METHOD1(onLayerDisplayed, void(std::shared_future)); MOCK_CONST_METHOD0(getDebugName, const char*()); MOCK_CONST_METHOD0(getSequence, int32_t()); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 048d7c2b4a..7ea1aa2f92 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -1097,12 +1098,12 @@ std::optional Output::composeSurfaces( setExpensiveRenderingExpected(true); } - std::vector clientCompositionLayerPointers; - clientCompositionLayerPointers.reserve(clientCompositionLayers.size()); + std::vector clientRenderEngineLayers; + clientRenderEngineLayers.reserve(clientCompositionLayers.size()); std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(), - std::back_inserter(clientCompositionLayerPointers), - [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings* { - return &settings; + std::back_inserter(clientRenderEngineLayers), + [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings { + return settings; }); const nsecs_t renderEngineStart = systemTime(); @@ -1115,7 +1116,7 @@ std::optional Output::composeSurfaces( const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay; auto [status, drawFence] = renderEngine - .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex, + .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, tex, useFramebufferCache, std::move(fd)) .get(); @@ -1295,8 +1296,10 @@ void Output::postFramebuffer() { releaseFence = Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence); } - - layer->getLayerFE().onLayerDisplayed(releaseFence); + layer->getLayerFE().onLayerDisplayed( + ftl::yield( + {NO_ERROR, base::unique_fd(releaseFence->dup())}) + .share()); } // We've got a list of layers needing fences, that are disjoint with @@ -1304,7 +1307,9 @@ void Output::postFramebuffer() { // supply them with the present fence. for (auto& weakLayer : mReleasedLayers) { if (auto layer = weakLayer.promote(); layer != nullptr) { - layer->onLayerDisplayed(frame.presentFence); + layer->onLayerDisplayed(ftl::yield( + {NO_ERROR, base::unique_fd(frame.presentFence->dup())}) + .share()); } } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index e6b716e8f2..ec52e59ab0 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -193,11 +193,6 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te clientCompositionList.cend()); } - std::vector layerSettingsPointers; - std::transform(layerSettings.cbegin(), layerSettings.cend(), - std::back_inserter(layerSettingsPointers), - [](const renderengine::LayerSettings& settings) { return &settings; }); - renderengine::LayerSettings blurLayerSettings; if (mBlurLayer) { auto blurSettings = targetSettings; @@ -212,7 +207,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te blurLayerSettings.name = std::string("blur layer"); // Clear out the shadow settings blurLayerSettings.shadow = {}; - layerSettingsPointers.push_back(&blurLayerSettings); + layerSettings.push_back(blurLayerSettings); } renderengine::LayerSettings holePunchSettings; @@ -230,7 +225,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te holePunchSettings.disableBlending = true; holePunchSettings.alpha = 0.0f; holePunchSettings.name = std::string("hole punch layer"); - layerSettingsPointers.push_back(&holePunchSettings); + layerSettings.push_back(holePunchSettings); // Add a solid background as the first layer in case there is no opaque // buffer behind the punch hole @@ -239,7 +234,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te holePunchBackgroundSettings.geometry.boundaries = holePunchSettings.geometry.boundaries; holePunchBackgroundSettings.geometry.positionTransform = holePunchSettings.geometry.positionTransform; - layerSettingsPointers.insert(layerSettingsPointers.begin(), &holePunchBackgroundSettings); + layerSettings.emplace(layerSettings.begin(), holePunchBackgroundSettings); } if (sDebugHighlighLayers) { @@ -257,7 +252,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te .alpha = half(0.05f), }; - layerSettingsPointers.emplace_back(&highlight); + layerSettings.emplace_back(highlight); } auto texture = texturePool.borrowTexture(); @@ -273,8 +268,8 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te } auto [status, drawFence] = renderEngine - .drawLayers(displaySettings, layerSettingsPointers, - texture->get(), false, std::move(bufferFence)) + .drawLayers(displaySettings, layerSettings, texture->get(), + false, std::move(bufferFence)) .get(); if (status == NO_ERROR) { diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 8f0028c399..cf63ef5183 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -2884,12 +2885,24 @@ TEST_F(OutputPostFramebufferTest, releaseFencesAreSentToLayerFE) { // are passed. This happens to work with the current implementation, but // would not survive certain calls like Fence::merge() which would return a // new instance. - EXPECT_CALL(*mLayer1.layerFE, - onLayerDisplayed(Property(&sp::get, Eq(layer1Fence.get())))); - EXPECT_CALL(*mLayer2.layerFE, - onLayerDisplayed(Property(&sp::get, Eq(layer2Fence.get())))); - EXPECT_CALL(*mLayer3.layerFE, - onLayerDisplayed(Property(&sp::get, Eq(layer3Fence.get())))); + base::unique_fd layer1FD(layer1Fence->dup()); + base::unique_fd layer2FD(layer2Fence->dup()); + base::unique_fd layer3FD(layer3Fence->dup()); + EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_)) + .WillOnce([&layer1FD](std::shared_future + futureRenderEngineResult) { + EXPECT_EQ(layer1FD, futureRenderEngineResult.get().drawFence); + }); + EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_)) + .WillOnce([&layer2FD](std::shared_future + futureRenderEngineResult) { + EXPECT_EQ(layer2FD, futureRenderEngineResult.get().drawFence); + }); + EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_)) + .WillOnce([&layer3FD](std::shared_future + futureRenderEngineResult) { + EXPECT_EQ(layer3FD, futureRenderEngineResult.get().drawFence); + }); mOutput.postFramebuffer(); } @@ -2915,9 +2928,9 @@ TEST_F(OutputPostFramebufferTest, releaseFencesIncludeClientTargetAcquireFence) // Fence::merge is called, and since none of the fences are actually valid, // Fence::NO_FENCE is returned and passed to each onLayerDisplayed() call. // This is the best we can do without creating a real kernel fence object. - EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(Fence::NO_FENCE)); - EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(Fence::NO_FENCE)); - EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(Fence::NO_FENCE)); + EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed).WillOnce(Return()); + EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed).WillOnce(Return()); + EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed).WillOnce(Return()); mOutput.postFramebuffer(); } @@ -2949,12 +2962,22 @@ TEST_F(OutputPostFramebufferTest, releasedLayersSentPresentFence) { EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted()); // Each released layer should be given the presentFence. - EXPECT_CALL(*releasedLayer1, - onLayerDisplayed(Property(&sp::get, Eq(presentFence.get())))); - EXPECT_CALL(*releasedLayer2, - onLayerDisplayed(Property(&sp::get, Eq(presentFence.get())))); - EXPECT_CALL(*releasedLayer3, - onLayerDisplayed(Property(&sp::get, Eq(presentFence.get())))); + base::unique_fd layerFD(presentFence.get()->dup()); + EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_)) + .WillOnce([&layerFD](std::shared_future + futureRenderEngineResult) { + EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence); + }); + EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_)) + .WillOnce([&layerFD](std::shared_future + futureRenderEngineResult) { + EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence); + }); + EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_)) + .WillOnce([&layerFD](std::shared_future + futureRenderEngineResult) { + EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence); + }); mOutput.postFramebuffer(); @@ -3131,9 +3154,9 @@ TEST_F(OutputComposeSurfacesTest, handlesZeroCompositionRequests) { EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); EXPECT_CALL(mRenderEngine, drawLayers(_, IsEmpty(), _, false, _)) .WillRepeatedly([&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd &&) + base::unique_fd&&) -> std::future { return futureOf({NO_ERROR, base::unique_fd()}); }); @@ -3161,11 +3184,11 @@ TEST_F(OutputComposeSurfacesTest, buildsAndRendersRequestList) { })); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) .WillRepeatedly([&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd &&) + base::unique_fd&&) -> std::future { return futureOf({NO_ERROR, base::unique_fd()}); }); @@ -3196,11 +3219,11 @@ TEST_F(OutputComposeSurfacesTest, })); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, true, _)) .WillRepeatedly([&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd &&) + base::unique_fd&&) -> std::future { return futureOf({NO_ERROR, base::unique_fd()}); }); @@ -3226,7 +3249,7 @@ TEST_F(OutputComposeSurfacesTest, renderDuplicateClientCompositionRequestsWithou .WillRepeatedly(Return()); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) .Times(2) .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))) @@ -3258,7 +3281,7 @@ TEST_F(OutputComposeSurfacesTest, skipDuplicateClientCompositionRequests) { .WillRepeatedly(Return()); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false)); @@ -3294,11 +3317,11 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) { EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)) .WillOnce(Return(mOutputBuffer)) .WillOnce(Return(otherOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) .WillRepeatedly([&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd &&) + base::unique_fd&&) -> std::future { return futureOf({NO_ERROR, base::unique_fd()}); }); @@ -3330,10 +3353,10 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfRequestChanges) { .WillRepeatedly(Return()); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r3), _, false, _)) .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); @@ -3487,9 +3510,9 @@ struct OutputComposeSurfacesTest_HandlesProtectedContent : public OutputComposeS EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _)) .WillRepeatedly( [&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { return futureOf( {NO_ERROR, base::unique_fd()}); }); diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index ecb05f8e5f..42b3d972a8 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -346,15 +346,15 @@ TEST_F(CachedSetTest, renderUnsecureOutput) { const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()), displaySettings.orientation); - EXPECT_EQ(0.5f, layers[0]->alpha); - EXPECT_EQ(0.75f, layers[1]->alpha); + EXPECT_EQ(0.5f, layers[0].alpha); + EXPECT_EQ(0.75f, layers[1].alpha); EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace); return futureOf({NO_ERROR, base::unique_fd()}); }; @@ -398,15 +398,15 @@ TEST_F(CachedSetTest, renderSecureOutput) { const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()), displaySettings.orientation); - EXPECT_EQ(0.5f, layers[0]->alpha); - EXPECT_EQ(0.75f, layers[1]->alpha); + EXPECT_EQ(0.5f, layers[0].alpha); + EXPECT_EQ(0.75f, layers[1].alpha); EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace); return futureOf({NO_ERROR, base::unique_fd()}); @@ -453,15 +453,15 @@ TEST_F(CachedSetTest, rendersWithOffsetFramebufferContent) { const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()), displaySettings.orientation); - EXPECT_EQ(0.5f, layers[0]->alpha); - EXPECT_EQ(0.75f, layers[1]->alpha); + EXPECT_EQ(0.5f, layers[0].alpha); + EXPECT_EQ(0.75f, layers[1].alpha); EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace); return futureOf({NO_ERROR, base::unique_fd()}); @@ -656,26 +656,26 @@ TEST_F(CachedSetTest, addHolePunch) { const auto drawLayers = [&](const renderengine::DisplaySettings&, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { // If the highlight layer is enabled, it will increase the size by 1. // We're interested in the third layer either way. EXPECT_GE(layers.size(), 4u); { - const auto* holePunchSettings = layers[3]; - EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor); - EXPECT_TRUE(holePunchSettings->disableBlending); - EXPECT_EQ(0.0f, holePunchSettings->alpha); + const auto holePunchSettings = layers[3]; + EXPECT_EQ(nullptr, holePunchSettings.source.buffer.buffer); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings.source.solidColor); + EXPECT_TRUE(holePunchSettings.disableBlending); + EXPECT_EQ(0.0f, holePunchSettings.alpha); } { - const auto* holePunchBackgroundSettings = layers[0]; - EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor); - EXPECT_FALSE(holePunchBackgroundSettings->disableBlending); - EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha); + const auto holePunchBackgroundSettings = layers[0]; + EXPECT_EQ(nullptr, holePunchBackgroundSettings.source.buffer.buffer); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings.source.solidColor); + EXPECT_FALSE(holePunchBackgroundSettings.disableBlending); + EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha); } return futureOf({NO_ERROR, base::unique_fd()}); @@ -717,27 +717,27 @@ TEST_F(CachedSetTest, addHolePunch_noBuffer) { const auto drawLayers = [&](const renderengine::DisplaySettings&, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { // If the highlight layer is enabled, it will increase the size by 1. // We're interested in the third layer either way. EXPECT_GE(layers.size(), 4u); { - const auto* holePunchSettings = layers[3]; - EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor); - EXPECT_TRUE(holePunchSettings->disableBlending); - EXPECT_EQ(0.0f, holePunchSettings->alpha); + const auto holePunchSettings = layers[3]; + EXPECT_EQ(nullptr, holePunchSettings.source.buffer.buffer); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings.source.solidColor); + EXPECT_TRUE(holePunchSettings.disableBlending); + EXPECT_EQ(0.0f, holePunchSettings.alpha); } { - const auto* holePunchBackgroundSettings = layers[0]; - EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor); - EXPECT_FALSE(holePunchBackgroundSettings->disableBlending); - EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha); + const auto holePunchBackgroundSettings = layers[0]; + EXPECT_EQ(nullptr, holePunchBackgroundSettings.source.buffer.buffer); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings.source.solidColor); + EXPECT_FALSE(holePunchBackgroundSettings.disableBlending); + EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha); } return futureOf({NO_ERROR, base::unique_fd()}); @@ -867,16 +867,16 @@ TEST_F(CachedSetTest, addBlur) { const auto drawLayers = [&](const renderengine::DisplaySettings&, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { // If the highlight layer is enabled, it will increase the size by 1. // We're interested in the third layer either way. EXPECT_GE(layers.size(), 3u); - const auto* blurSettings = layers[2]; - EXPECT_TRUE(blurSettings->skipContentDraw); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings->source.solidColor); - EXPECT_EQ(0.0f, blurSettings->alpha); + const auto blurSettings = layers[2]; + EXPECT_TRUE(blurSettings.skipContentDraw); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings.source.solidColor); + EXPECT_EQ(0.0f, blurSettings.alpha); return futureOf({NO_ERROR, base::unique_fd()}); }; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5707c67a56..d68cf9720f 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -221,7 +221,8 @@ LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp client, * Layer. So, the implementation is done in BufferLayer. When called on a * EffectLayer object, it's essentially a NOP. */ -void Layer::onLayerDisplayed(const sp& /*releaseFence*/) {} +void Layer::onLayerDisplayed( + std::shared_future /*futureRenderEngineResult*/) {} void Layer::removeRelativeZ(const std::vector& layersInTree) { if (mDrawingState.zOrderRelativeOf == nullptr) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 07b2eb5130..4569f9af23 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -616,7 +616,8 @@ public: void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override; std::vector prepareClientCompositionList( compositionengine::LayerFE::ClientCompositionTargetSettings&) override; - void onLayerDisplayed(const sp& releaseFence) override; + void onLayerDisplayed( + std::shared_future futureRenderEngineResult) override; void setWasClientComposed(const sp& fence) override { mLastClientCompositionFence = fence; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index aa2fec56ad..d0f56b5bdd 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -356,10 +356,13 @@ void RegionSamplingThread::captureSample() { renderengine::ExternalTexture::Usage::WRITEABLE); } - const sp captureListener = new SyncScreenCaptureListener(); - mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - true /* regionSampling */, false /* grayscale */, captureListener); - ScreenCaptureResults captureResults = captureListener->waitForResults(); + auto captureScreenResultFuture = + mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, + true /* regionSampling */, false /* grayscale */, nullptr); + auto& captureScreenResult = captureScreenResultFuture.get(); + if (captureScreenResult.drawFence.ok()) { + sync_wait(captureScreenResult.drawFence.get(), -1); + } std::vector activeDescriptors; for (const auto& descriptor : descriptors) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index acb81dc41c..638458cfd3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5972,9 +5972,10 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, traverseLayersInLayerStack(layerStack, args.uid, visitor); }; - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, args.allowProtected, args.grayscale, - captureListener); + auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, + reqSize, args.pixelFormat, args.allowProtected, + args.grayscale, captureListener); + return captureResultFuture.get().status; } status_t SurfaceFlinger::captureDisplay(DisplayId displayId, @@ -6009,9 +6010,15 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId, traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor); }; - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, - ui::PixelFormat::RGBA_8888, false /* allowProtected */, - false /* grayscale */, captureListener); + if (captureListener == nullptr) { + ALOGE("capture screen must provide a capture listener callback"); + return BAD_VALUE; + } + auto captureResultFuture = + captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, + ui::PixelFormat::RGBA_8888, false /* allowProtected */, + false /* grayscale */, captureListener); + return captureResultFuture.get().status; } status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, @@ -6138,23 +6145,28 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, }); }; - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, args.allowProtected, args.grayscale, - captureListener); + if (captureListener == nullptr) { + ALOGE("capture screen must provide a capture listener callback"); + return BAD_VALUE; + } + + auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, + reqSize, args.pixelFormat, args.allowProtected, + args.grayscale, captureListener); + return captureResultFuture.get().status; } -status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, - TraverseLayersFunction traverseLayers, - ui::Size bufferSize, ui::PixelFormat reqPixelFormat, - bool allowProtected, bool grayscale, - const sp& captureListener) { +std::shared_future SurfaceFlinger::captureScreenCommon( + RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, + ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale, + const sp& captureListener) { ATRACE_CALL(); if (exceedsMaxRenderTargetSize(bufferSize.getWidth(), bufferSize.getHeight())) { ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32 ") that exceeds render target size limit.", bufferSize.getWidth(), bufferSize.getHeight()); - return BAD_VALUE; + return ftl::yield({BAD_VALUE, base::unique_fd()}).share(); } // Loop over all visible layers to see whether there's any protected layer. A protected layer is @@ -6194,25 +6206,23 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, false /* regionSampling */, grayscale, captureListener); } -status_t SurfaceFlinger::captureScreenCommon( +std::shared_future SurfaceFlinger::captureScreenCommon( RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, const std::shared_ptr& buffer, bool regionSampling, bool grayscale, const sp& captureListener) { ATRACE_CALL(); - if (captureListener == nullptr) { - ALOGE("capture screen must provide a capture listener callback"); - return BAD_VALUE; - } - bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission(); - static_cast(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable { + auto scheduleResultFuture = schedule([=, + renderAreaFuture = std::move(renderAreaFuture)]() mutable + -> std::shared_future { if (mRefreshPending) { ALOGW("Skipping screenshot for now"); captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, regionSampling, grayscale, captureListener); - return; + return ftl::yield({NO_ERROR, base::unique_fd()}) + .share(); } ScreenCaptureResults captureResults; std::unique_ptr renderArea = renderAreaFuture.get(); @@ -6220,24 +6230,44 @@ status_t SurfaceFlinger::captureScreenCommon( ALOGW("Skipping screen capture because of invalid render area."); captureResults.result = NO_MEMORY; captureListener->onScreenCaptureCompleted(captureResults); - return; + return ftl::yield({NO_ERROR, base::unique_fd()}) + .share(); } - status_t result = NO_ERROR; + std::shared_future renderEngineResultFuture; + renderArea->render([&] { - result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, - canCaptureBlackoutContent, regionSampling, grayscale, - captureResults); + renderEngineResultFuture = + renderScreenImplLocked(*renderArea, traverseLayers, buffer, + canCaptureBlackoutContent, regionSampling, grayscale, + captureResults); }); + // spring up a thread to unblock SF main thread and wait for + // RenderEngineResult to be available + if (captureListener != nullptr) { + std::async([=]() mutable { + ATRACE_NAME("captureListener is nonnull!"); + auto& [status, drawFence] = renderEngineResultFuture.get(); + captureResults.result = status; + captureResults.fence = new Fence(dup(drawFence)); + captureListener->onScreenCaptureCompleted(captureResults); + }); + } + return renderEngineResultFuture; + }); - captureResults.result = result; - captureListener->onScreenCaptureCompleted(captureResults); - })); - - return NO_ERROR; + // flatten scheduleResultFuture object to single shared_future object + std::future captureScreenResultFuture = + ftl::chain(std::move(scheduleResultFuture)) + .then([=](std::shared_future futureObject) + -> renderengine::RenderEngineResult { + auto& [status, drawFence] = futureObject.get(); + return {status, base::unique_fd(dup(drawFence))}; + }); + return captureScreenResultFuture.share(); } -status_t SurfaceFlinger::renderScreenImplLocked( +std::shared_future SurfaceFlinger::renderScreenImplLocked( const RenderArea& renderArea, TraverseLayersFunction traverseLayers, const std::shared_ptr& buffer, bool canCaptureBlackoutContent, bool regionSampling, bool grayscale, @@ -6256,7 +6286,8 @@ status_t SurfaceFlinger::renderScreenImplLocked( // the impetus on WindowManager to not persist them. if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) { ALOGW("FB is protected: PERMISSION_DENIED"); - return PERMISSION_DENIED; + return ftl::yield({PERMISSION_DENIED, base::unique_fd()}) + .share(); } captureResults.buffer = buffer->getBuffer(); @@ -6338,11 +6369,12 @@ status_t SurfaceFlinger::renderScreenImplLocked( }); - std::vector clientCompositionLayerPointers( - clientCompositionLayers.size()); + std::vector clientRenderEngineLayers; + clientRenderEngineLayers.reserve(clientCompositionLayers.size()); std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(), - clientCompositionLayerPointers.begin(), - std::pointer_traits::pointer_to); + std::back_inserter(clientRenderEngineLayers), + [](compositionengine::LayerFE::LayerSettings& settings) + -> renderengine::LayerSettings { return settings; }); // Use an empty fence for the buffer fence, since we just created the buffer so // there is no need for synchronization with the GPU. @@ -6350,24 +6382,22 @@ status_t SurfaceFlinger::renderScreenImplLocked( getRenderEngine().useProtectedContext(useProtected); const constexpr bool kUseFramebufferCache = false; - auto [status, drawFence] = - getRenderEngine() - .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer, - kUseFramebufferCache, std::move(bufferFence)) - .get(); + std::future drawLayersResult = + getRenderEngine().drawLayers(clientCompositionDisplay, clientRenderEngineLayers, buffer, + kUseFramebufferCache, std::move(bufferFence)); - if (drawFence >= 0) { - sp releaseFence = new Fence(dup(drawFence)); - for (auto* layer : renderedLayers) { - layer->onLayerDisplayed(releaseFence); - } + std::shared_future drawLayersResultFuture = + drawLayersResult.share(); // drawLayersResult will be moved to shared one + + for (auto* layer : renderedLayers) { + // make a copy of shared_future object for each layer + layer->onLayerDisplayed(drawLayersResultFuture); } - captureResults.fence = new Fence(drawFence.release()); // Always switch back to unprotected context. getRenderEngine().useProtectedContext(false); - return status; + return drawLayersResultFuture; } void SurfaceFlinger::windowInfosReported() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 1f0e42ddf3..45fd94e50c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -906,17 +906,17 @@ private: // Boot animation, on/off animations and screen capture void startBootAnim(); - 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&, - bool regionSampling, bool grayscale, - const sp&); - status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction, - const std::shared_ptr&, - bool canCaptureBlackoutContent, bool regionSampling, - bool grayscale, ScreenCaptureResults&); + std::shared_future captureScreenCommon( + RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, ui::PixelFormat, + bool allowProtected, bool grayscale, const sp&); + std::shared_future captureScreenCommon( + RenderAreaFuture, TraverseLayersFunction, + const std::shared_ptr&, bool regionSampling, + bool grayscale, const sp&); + std::shared_future renderScreenImplLocked( + const RenderArea&, TraverseLayersFunction, + const std::shared_ptr&, bool canCaptureBlackoutContent, + bool regionSampling, bool grayscale, ScreenCaptureResults&); // If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a // matching ownerUid diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index c1eb8966d1..8fbf0b4d07 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -154,6 +154,38 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp& // destroyed the client side is dead and there won't be anyone to send the callback to. sp surfaceControl = handle->surfaceControl.promote(); if (surfaceControl) { + sp prevFence = nullptr; + + for (const auto& futureStruct : handle->previousReleaseFences) { + sp currentFence = sp::make(dup(futureStruct.get().drawFence)); + if (prevFence == nullptr && currentFence->getStatus() != Fence::Status::Invalid) { + prevFence = currentFence; + handle->previousReleaseFence = prevFence; + } else if (prevFence != nullptr) { + // If both fences are signaled or both are unsignaled, we need to merge + // them to get an accurate timestamp. + if (prevFence->getStatus() != Fence::Status::Invalid && + prevFence->getStatus() == currentFence->getStatus()) { + char fenceName[32] = {}; + snprintf(fenceName, 32, "%.28s", handle->name.c_str()); + sp mergedFence = Fence::merge(fenceName, prevFence, currentFence); + if (mergedFence->isValid()) { + handle->previousReleaseFence = mergedFence; + prevFence = handle->previousReleaseFence; + } + } else if (currentFence->getStatus() == Fence::Status::Unsignaled) { + // If one fence has signaled and the other hasn't, the unsignaled + // fence will approximately correspond with the correct timestamp. + // There's a small race if both fences signal at about the same time + // and their statuses are retrieved with unfortunate timing. However, + // by this point, they will have both signaled and only the timestamp + // will be slightly off; any dependencies after this point will + // already have been met. + handle->previousReleaseFence = currentFence; + } + } + } + handle->previousReleaseFences = {}; FrameEventHistoryStats eventStats(handle->frameNumber, handle->gpuCompositionDoneFence->getSnapshot().fence, handle->compositorTiming, handle->refreshStartTime, diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index 7e879e119b..100dbfa8aa 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -18,8 +18,9 @@ #include #include -#include +#include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include +#include #include namespace android { @@ -42,7 +44,9 @@ public: wp surfaceControl; bool releasePreviousBuffer = false; + std::string name; sp previousReleaseFence; + std::vector> previousReleaseFences; nsecs_t acquireTime = -1; nsecs_t latchTime = -1; uint32_t transformHint = 0; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 5135ff952f..61c7c398dd 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -247,10 +247,16 @@ void CompositionTest::captureScreenComposition() { "screenshot"), *mRenderEngine, true); - status_t result = - mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer, - forSystem, regionSampling); - EXPECT_EQ(NO_ERROR, result); + auto result = mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer, + forSystem, regionSampling); + EXPECT_TRUE(result.valid()); + + auto& [status, drawFence] = result.get(); + + EXPECT_EQ(NO_ERROR, status); + if (drawFence.ok()) { + sync_wait(drawFence.get(), -1); + } LayerCase::cleanup(this); } @@ -346,9 +352,9 @@ struct BaseDisplayVariant { static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings, - const std::vector&, + const std::vector&, const std::shared_ptr&, - const bool, base::unique_fd &&) + const bool, base::unique_fd&&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), @@ -397,9 +403,9 @@ struct BaseDisplayVariant { Return(0))); EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings, - const std::vector&, + const std::vector&, const std::shared_ptr&, - const bool, base::unique_fd &&) + const bool, base::unique_fd&&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), @@ -633,9 +639,9 @@ struct BaseLayerProperties { static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layerSettings, + const std::vector& layerSettings, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -652,16 +658,16 @@ struct BaseLayerProperties { "verification lambda"; return resultFuture; } - const renderengine::LayerSettings* layer = layerSettings.back(); - EXPECT_THAT(layer->source.buffer.buffer, Not(IsNull())); - EXPECT_THAT(layer->source.buffer.fence, Not(IsNull())); - EXPECT_EQ(DEFAULT_TEXTURE_ID, layer->source.buffer.textureName); - EXPECT_EQ(false, layer->source.buffer.isY410BT2020); - EXPECT_EQ(true, layer->source.buffer.usePremultipliedAlpha); - EXPECT_EQ(false, layer->source.buffer.isOpaque); - EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius); - EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace); - EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha); + const renderengine::LayerSettings layer = layerSettings.back(); + EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull())); + EXPECT_THAT(layer.source.buffer.fence, Not(IsNull())); + EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName); + EXPECT_EQ(false, layer.source.buffer.isY410BT2020); + EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha); + EXPECT_EQ(false, layer.source.buffer.isOpaque); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); + EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); + EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha); return resultFuture; }); } @@ -685,9 +691,9 @@ struct BaseLayerProperties { static void setupREColorCompositionCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layerSettings, + const std::vector& layerSettings, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -704,14 +710,14 @@ struct BaseLayerProperties { "setupREColorCompositionCallExpectations verification lambda"; return resultFuture; } - const renderengine::LayerSettings* layer = layerSettings.back(); - EXPECT_THAT(layer->source.buffer.buffer, IsNull()); + const renderengine::LayerSettings layer = layerSettings.back(); + EXPECT_THAT(layer.source.buffer.buffer, IsNull()); EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1], LayerProperties::COLOR[2]), - layer->source.solidColor); - EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius); - EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace); - EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha); + layer.source.solidColor); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); + EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); + EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha); return resultFuture; }); } @@ -765,9 +771,9 @@ struct CommonSecureLayerProperties : public BaseLayerProperties static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layerSettings, + const std::vector& layerSettings, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -784,12 +790,12 @@ struct CommonSecureLayerProperties : public BaseLayerProperties "verification lambda"; return resultFuture; } - const renderengine::LayerSettings* layer = layerSettings.back(); - EXPECT_THAT(layer->source.buffer.buffer, IsNull()); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer->source.solidColor); - EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius); - EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace); - EXPECT_EQ(1.0f, layer->alpha); + const renderengine::LayerSettings layer = layerSettings.back(); + EXPECT_THAT(layer.source.buffer.buffer, IsNull()); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); + EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); + EXPECT_EQ(1.0f, layer.alpha); return resultFuture; }); } -- cgit v1.2.3-59-g8ed1b From 2109270e74a18585aceffc94d1758cee47bb4175 Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Tue, 12 Oct 2021 12:43:47 +0000 Subject: Revert "Second Patch for async RenderEngine" Revert "Fix vender implementation due to second patch of async R..." Revert submission 15644535-asyncRenderEngineV2 Reason for revert: Broke multiple tests Reverted Changes: I772122750:Fix vts cases due to function change for async ren... I615f2927d:Second Patch for async RenderEngine I3f47b8b67:Fix vender implementation due to second patch of a... Bug: 202803359 Bug: 202808760 Change-Id: Ib8ef68747621b7114cf2d1dfb856292674729744 --- libs/renderengine/RenderEngine.cpp | 2 +- libs/renderengine/gl/GLESRenderEngine.cpp | 66 +++++------ libs/renderengine/gl/GLESRenderEngine.h | 2 +- .../include/renderengine/RenderEngine.h | 4 +- .../include/renderengine/mock/RenderEngine.h | 4 +- libs/renderengine/skia/Cache.cpp | 16 +-- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 113 +++++++++--------- libs/renderengine/skia/SkiaGLRenderEngine.h | 7 +- libs/renderengine/skia/SkiaRenderEngine.h | 2 +- libs/renderengine/tests/RenderEngineTest.cpp | 125 ++++++++++--------- .../tests/RenderEngineThreadedTest.cpp | 7 +- .../renderengine/threaded/RenderEngineThreaded.cpp | 11 +- libs/renderengine/threaded/RenderEngineThreaded.h | 4 +- services/surfaceflinger/BufferQueueLayer.cpp | 4 +- services/surfaceflinger/BufferQueueLayer.h | 3 +- services/surfaceflinger/BufferStateLayer.cpp | 88 +++++++++++--- services/surfaceflinger/BufferStateLayer.h | 8 +- .../include/compositionengine/LayerFE.h | 4 +- .../include/compositionengine/mock/LayerFE.h | 2 +- .../CompositionEngine/src/Output.cpp | 23 ++-- .../CompositionEngine/src/planner/CachedSet.cpp | 17 ++- .../CompositionEngine/tests/OutputTest.cpp | 87 +++++--------- .../tests/planner/CachedSetTest.cpp | 84 ++++++------- services/surfaceflinger/Layer.cpp | 3 +- services/surfaceflinger/Layer.h | 3 +- services/surfaceflinger/RegionSamplingThread.cpp | 11 +- services/surfaceflinger/SurfaceFlinger.cpp | 132 ++++++++------------- services/surfaceflinger/SurfaceFlinger.h | 22 ++-- .../surfaceflinger/TransactionCallbackInvoker.cpp | 32 ----- .../surfaceflinger/TransactionCallbackInvoker.h | 6 +- .../tests/unittests/CompositionTest.cpp | 78 ++++++------ 31 files changed, 457 insertions(+), 513 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index a9ea690a7c..2174df5515 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -96,7 +96,7 @@ void RenderEngine::validateOutputBufferUsage(const sp& buffer) { } std::future RenderEngine::drawLayers( - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { const auto resultPromise = std::make_shared>(); diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 22dd86698b..2375cb7bf1 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -1080,7 +1080,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer void GLESRenderEngine::drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { ATRACE_CALL(); @@ -1110,10 +1110,10 @@ void GLESRenderEngine::drawLayersInternal( std::unique_ptr fbo; // Gathering layers that requested blur, we'll need them to decide when to render to an // offscreen buffer, and when to render to the native buffer. - std::deque blurLayers; + std::deque blurLayers; if (CC_LIKELY(mBlurFilter != nullptr)) { - for (const auto& layer : layers) { - if (layer.backgroundBlurRadius > 0) { + for (auto layer : layers) { + if (layer->backgroundBlurRadius > 0) { blurLayers.push_back(layer); } } @@ -1137,7 +1137,7 @@ void GLESRenderEngine::drawLayersInternal( } else { setViewportAndProjection(display.physicalDisplay, display.clip); auto status = - mBlurFilter->setAsDrawTarget(display, blurLayers.front().backgroundBlurRadius); + 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); @@ -1167,7 +1167,7 @@ void GLESRenderEngine::drawLayersInternal( .setTexCoords(2 /* size */) .setCropCoords(2 /* size */) .build(); - for (const auto& layer : layers) { + for (auto const layer : layers) { if (blurLayers.size() > 0 && blurLayers.front() == layer) { blurLayers.pop_front(); @@ -1193,7 +1193,7 @@ void GLESRenderEngine::drawLayersInternal( // There's still something else to blur, so let's keep rendering to our FBO // instead of to the display. status = mBlurFilter->setAsDrawTarget(display, - blurLayers.front().backgroundBlurRadius); + blurLayers.front()->backgroundBlurRadius); } if (status != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", @@ -1214,42 +1214,42 @@ void GLESRenderEngine::drawLayersInternal( } // Ensure luminance is at least 100 nits to avoid div-by-zero - const float maxLuminance = std::max(100.f, layer.source.buffer.maxLuminanceNits); + const float maxLuminance = std::max(100.f, layer->source.buffer.maxLuminanceNits); mState.maxMasteringLuminance = maxLuminance; mState.maxContentLuminance = maxLuminance; - mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform; + mState.projectionMatrix = projectionMatrix * layer->geometry.positionTransform; - const FloatRect bounds = layer.geometry.boundaries; + const FloatRect bounds = layer->geometry.boundaries; Mesh::VertexArray position(mesh.getPositionArray()); position[0] = vec2(bounds.left, bounds.top); position[1] = vec2(bounds.left, bounds.bottom); position[2] = vec2(bounds.right, bounds.bottom); position[3] = vec2(bounds.right, bounds.top); - setupLayerCropping(layer, mesh); - setColorTransform(layer.colorTransform); + setupLayerCropping(*layer, mesh); + setColorTransform(layer->colorTransform); bool usePremultipliedAlpha = true; bool disableTexture = true; bool isOpaque = false; - if (layer.source.buffer.buffer != nullptr) { + if (layer->source.buffer.buffer != nullptr) { disableTexture = false; - isOpaque = layer.source.buffer.isOpaque; + isOpaque = layer->source.buffer.isOpaque; - sp gBuf = layer.source.buffer.buffer->getBuffer(); + sp gBuf = layer->source.buffer.buffer->getBuffer(); validateInputBufferUsage(gBuf); - bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf, - layer.source.buffer.fence); + bindExternalTextureBuffer(layer->source.buffer.textureName, gBuf, + layer->source.buffer.fence); - usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha; - Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName); - mat4 texMatrix = layer.source.buffer.textureTransform; + usePremultipliedAlpha = layer->source.buffer.usePremultipliedAlpha; + Texture texture(Texture::TEXTURE_EXTERNAL, layer->source.buffer.textureName); + mat4 texMatrix = layer->source.buffer.textureTransform; texture.setMatrix(texMatrix.asArray()); - texture.setFiltering(layer.source.buffer.useTextureFiltering); + texture.setFiltering(layer->source.buffer.useTextureFiltering); texture.setDimensions(gBuf->getWidth(), gBuf->getHeight()); - setSourceY410BT2020(layer.source.buffer.isY410BT2020); + setSourceY410BT2020(layer->source.buffer.isY410BT2020); renderengine::Mesh::VertexArray texCoords(mesh.getTexCoordArray()); texCoords[0] = vec2(0.0, 0.0); @@ -1264,32 +1264,32 @@ void GLESRenderEngine::drawLayersInternal( } } - const half3 solidColor = layer.source.solidColor; - const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha); + const half3 solidColor = layer->source.solidColor; + const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer->alpha); // Buffer sources will have a black solid color ignored in the shader, // so in that scenario the solid color passed here is arbitrary. setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, - layer.geometry.roundedCornersRadius); - if (layer.disableBlending) { + layer->geometry.roundedCornersRadius); + if (layer->disableBlending) { glDisable(GL_BLEND); } - setSourceDataSpace(layer.sourceDataspace); + setSourceDataSpace(layer->sourceDataspace); - if (layer.shadow.length > 0.0f) { - handleShadow(layer.geometry.boundaries, layer.geometry.roundedCornersRadius, - layer.shadow); + if (layer->shadow.length > 0.0f) { + handleShadow(layer->geometry.boundaries, layer->geometry.roundedCornersRadius, + layer->shadow); } // We only want to do a special handling for rounded corners when having rounded corners // is the only reason it needs to turn on blending, otherwise, we handle it like the // usual way since it needs to turn on blending anyway. - else if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) { - handleRoundedCorners(display, layer, mesh); + else if (layer->geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) { + handleRoundedCorners(display, *layer, mesh); } else { drawMesh(mesh); } // Cleanup if there's a buffer source - if (layer.source.buffer.buffer != nullptr) { + if (layer->source.buffer.buffer != nullptr) { disableBlending(); setSourceY410BT2020(false); disableTexturing(); diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 1d7c2cafb5..c4adfdf752 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -104,7 +104,7 @@ protected: bool canSkipPostRenderCleanup() const override; void drawLayersInternal(const std::shared_ptr>&& resultPromise, const DisplaySettings& display, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index b9cc6485e5..701c1f2071 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -160,7 +160,7 @@ public: // @return A future object of RenderEngineResult struct indicating whether // drawing was successful in async mode. virtual std::future drawLayers( - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence); @@ -231,7 +231,7 @@ protected: virtual void drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) = 0; }; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index 248bd652c0..a7e6809223 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -49,12 +49,12 @@ public: MOCK_CONST_METHOD0(canSkipPostRenderCleanup, bool()); MOCK_METHOD5(drawLayers, std::future(const DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, base::unique_fd&&)); MOCK_METHOD6(drawLayersInternal, void(const std::shared_ptr>&&, - const DisplaySettings&, const std::vector&, + const DisplaySettings&, const std::vector&, const std::shared_ptr&, const bool, base::unique_fd&&)); MOCK_METHOD0(cleanFramebufferCache, void()); MOCK_METHOD0(getContextPriority, int()); diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index b18a872836..c4fa1bb091 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -95,7 +95,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin .alpha = 1, }; - auto layers = std::vector{layer, caster}; + auto layers = std::vector{&layer, &caster}; // Four combinations of settings are used (two transforms here, and drawShadowLayers is // called with two different destination data spaces) They're all rounded rect. // Three of these are cache misses that generate new shaders. @@ -140,7 +140,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting }}, }; - auto layers = std::vector{layer}; + auto layers = std::vector{&layer}; for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) { layer.sourceDataspace = dataspace; // Cache shaders for both rects and round rects. @@ -176,7 +176,7 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting .alpha = 0.5, }; - auto layers = std::vector{layer}; + auto layers = std::vector{&layer}; for (auto transform : {mat4(), kScaleAndTranslate}) { layer.geometry.positionTransform = transform; for (float roundedCornersRadius : {0.0f, 50.f}) { @@ -201,7 +201,7 @@ static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings .skipContentDraw = true, }; - auto layers = std::vector{layer}; + auto layers = std::vector{&layer}; // Different blur code is invoked for radii less and greater than 30 pixels for (int radius : {9, 60}) { layer.backgroundBlurRadius = radius; @@ -242,7 +242,7 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti }, }; - auto layers = std::vector{layer}; + auto layers = std::vector{&layer}; for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) { layer.source = pixelSource; for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) { @@ -289,7 +289,7 @@ static void drawPIPImageLayer(SkiaRenderEngine* renderengine, const DisplaySetti }; - auto layers = std::vector{layer}; + auto layers = std::vector{&layer}; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd()); } @@ -317,7 +317,7 @@ static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySett }; - auto layers = std::vector{layer}; + auto layers = std::vector{&layer}; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd()); } @@ -429,7 +429,7 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { LayerSettings layer{ .source = PixelSource{.solidColor = half3(0.f, 0.f, 0.f)}, }; - auto layers = std::vector{layer}; + auto layers = std::vector{&layer}; // call get() to make it synchronous renderengine ->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd()) diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index d5ec774e9c..cb686a643a 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -610,18 +610,17 @@ private: AutoBackendTexture::CleanupManager& mMgr; }; -sk_sp SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp shader, - const LayerSettings& layer, - const DisplaySettings& display, - bool undoPremultipliedAlpha, - bool requiresLinearEffect) { - const auto stretchEffect = layer.stretchEffect; +sk_sp SkiaGLRenderEngine::createRuntimeEffectShader( + sk_sp shader, + const LayerSettings* layer, const DisplaySettings& display, bool undoPremultipliedAlpha, + bool requiresLinearEffect) { + const auto stretchEffect = layer->stretchEffect; // The given surface will be stretched by HWUI via matrix transformation // which gets similar results for most surfaces // Determine later on if we need to leverage the stertch shader within // surface flinger if (stretchEffect.hasEffect()) { - const auto targetBuffer = layer.source.buffer.buffer; + const auto targetBuffer = layer->source.buffer.buffer; const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr; if (graphicBuffer && shader) { shader = mStretchShaderFactory.createSkShader(shader, stretchEffect); @@ -630,7 +629,7 @@ sk_sp SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp sh if (requiresLinearEffect) { const ui::Dataspace inputDataspace = - mUseColorManagement ? layer.sourceDataspace : ui::Dataspace::V0_SRGB_LINEAR; + mUseColorManagement ? layer->sourceDataspace : ui::Dataspace::V0_SRGB_LINEAR; const ui::Dataspace outputDataspace = mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR; @@ -646,13 +645,13 @@ sk_sp SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp sh } else { runtimeEffect = effectIter->second; } - float maxLuminance = layer.source.buffer.maxLuminanceNits; + 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, + return createLinearEffectShader(shader, effect, runtimeEffect, layer->colorTransform, display.maxLuminance, maxLuminance); } return shader; @@ -730,7 +729,7 @@ static SkRRect getBlurRRect(const BlurRegion& region) { void SkiaGLRenderEngine::drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool /*useFramebufferCache*/, base::unique_fd&& bufferFence) { ATRACE_NAME("SkiaGL::drawLayers"); @@ -802,11 +801,11 @@ void SkiaGLRenderEngine::drawLayersInternal( if (!layerHasBlur(layer, ctModifiesAlpha)) { continue; } - if (layer.backgroundBlurRadius > 0 && - layer.backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) { + if (layer->backgroundBlurRadius > 0 && + layer->backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) { requiresCompositionLayer = true; } - for (auto region : layer.blurRegions) { + for (auto region : layer->blurRegions) { if (region.blurRadius < BlurFilter::kMaxCrossFadeRadius) { requiresCompositionLayer = true; } @@ -814,7 +813,7 @@ void SkiaGLRenderEngine::drawLayersInternal( if (requiresCompositionLayer) { activeSurface = dstSurface->makeSurface(dstSurface->imageInfo()); canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState); - blurCompositionLayer = &layer; + blurCompositionLayer = layer; break; } } @@ -826,11 +825,11 @@ void SkiaGLRenderEngine::drawLayersInternal( initCanvas(canvas, display); for (const auto& layer : layers) { - ATRACE_FORMAT("DrawLayer: %s", layer.name.c_str()); + ATRACE_FORMAT("DrawLayer: %s", layer->name.c_str()); if (kPrintLayerSettings) { std::stringstream ls; - PrintTo(layer, &ls); + PrintTo(*layer, &ls); auto debugs = ls.str(); int pos = 0; while (pos < debugs.size()) { @@ -840,7 +839,7 @@ void SkiaGLRenderEngine::drawLayersInternal( } sk_sp blurInput; - if (blurCompositionLayer == &layer) { + if (blurCompositionLayer == layer) { LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface); LOG_ALWAYS_FATAL_IF(canvas == dstCanvas); @@ -879,17 +878,17 @@ void SkiaGLRenderEngine::drawLayersInternal( if (CC_UNLIKELY(mCapture->isCaptureRunning())) { // Record the name of the layer if the capture is running. std::stringstream layerSettings; - PrintTo(layer, &layerSettings); + PrintTo(*layer, &layerSettings); // Store the LayerSettings in additional information. - canvas->drawAnnotation(SkRect::MakeEmpty(), layer.name.c_str(), + canvas->drawAnnotation(SkRect::MakeEmpty(), layer->name.c_str(), SkData::MakeWithCString(layerSettings.str().c_str())); } // Layers have a local transform that should be applied to them - canvas->concat(getSkM44(layer.geometry.positionTransform).asM33()); + canvas->concat(getSkM44(layer->geometry.positionTransform).asM33()); const auto [bounds, roundRectClip] = - getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop, - layer.geometry.roundedCornersRadius); + getBoundsAndClip(layer->geometry.boundaries, layer->geometry.roundedCornersCrop, + layer->geometry.roundedCornersRadius); if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) { std::unordered_map> cachedBlurs; @@ -910,19 +909,20 @@ void SkiaGLRenderEngine::drawLayersInternal( // TODO(b/182216890): Filter out empty layers earlier if (blurRect.width() > 0 && blurRect.height() > 0) { - if (layer.backgroundBlurRadius > 0) { + if (layer->backgroundBlurRadius > 0) { ATRACE_NAME("BackgroundBlur"); - auto blurredImage = mBlurFilter->generate(grContext, layer.backgroundBlurRadius, - blurInput, blurRect); + auto blurredImage = + mBlurFilter->generate(grContext, layer->backgroundBlurRadius, blurInput, + blurRect); - cachedBlurs[layer.backgroundBlurRadius] = blurredImage; + cachedBlurs[layer->backgroundBlurRadius] = blurredImage; - mBlurFilter->drawBlurRegion(canvas, bounds, layer.backgroundBlurRadius, 1.0f, + mBlurFilter->drawBlurRegion(canvas, bounds, layer->backgroundBlurRadius, 1.0f, blurRect, blurredImage, blurInput); } - canvas->concat(getSkM44(layer.blurRegionTransform).asM33()); - for (auto region : layer.blurRegions) { + canvas->concat(getSkM44(layer->blurRegionTransform).asM33()); + for (auto region : layer->blurRegions) { if (cachedBlurs[region.blurRadius] == nullptr) { ATRACE_NAME("BlurRegion"); cachedBlurs[region.blurRadius] = @@ -937,18 +937,19 @@ void SkiaGLRenderEngine::drawLayersInternal( } } - if (layer.shadow.length > 0) { + if (layer->shadow.length > 0) { // This would require a new parameter/flag to SkShadowUtils::DrawShadow - LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow"); + LOG_ALWAYS_FATAL_IF(layer->disableBlending, "Cannot disableBlending with a shadow"); SkRRect shadowBounds, shadowClip; - if (layer.geometry.boundaries == layer.shadow.boundaries) { + if (layer->geometry.boundaries == layer->shadow.boundaries) { shadowBounds = bounds; shadowClip = roundRectClip; } else { std::tie(shadowBounds, shadowClip) = - getBoundsAndClip(layer.shadow.boundaries, layer.geometry.roundedCornersCrop, - layer.geometry.roundedCornersRadius); + getBoundsAndClip(layer->shadow.boundaries, + layer->geometry.roundedCornersCrop, + layer->geometry.roundedCornersRadius); } // Technically, if bounds is a rect and roundRectClip is not empty, @@ -959,18 +960,18 @@ void SkiaGLRenderEngine::drawLayersInternal( // looks more like the intent. const auto& rrect = shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds; - drawShadow(canvas, rrect, layer.shadow); + drawShadow(canvas, rrect, layer->shadow); } - const bool requiresLinearEffect = layer.colorTransform != mat4() || + 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.skipContentDraw || - (layer.alpha == 0 && !requiresLinearEffect && !layer.disableBlending && + if (layer->skipContentDraw || + (layer->alpha == 0 && !requiresLinearEffect && !layer->disableBlending && (!displayColorTransform || displayColorTransform->isAlphaUnchanged()))) { continue; } @@ -980,13 +981,13 @@ void SkiaGLRenderEngine::drawLayersInternal( // management is a no-op. const ui::Dataspace layerDataspace = (!mUseColorManagement || requiresLinearEffect) ? dstDataspace - : layer.sourceDataspace; + : layer->sourceDataspace; SkPaint paint; - if (layer.source.buffer.buffer) { + if (layer->source.buffer.buffer) { ATRACE_NAME("DrawImage"); - validateInputBufferUsage(layer.source.buffer.buffer->getBuffer()); - const auto& item = layer.source.buffer; + validateInputBufferUsage(layer->source.buffer.buffer->getBuffer()); + const auto& item = layer->source.buffer; std::shared_ptr imageTextureRef = nullptr; if (const auto& iter = cache.find(item.buffer->getBuffer()->getId()); @@ -1005,8 +1006,8 @@ void SkiaGLRenderEngine::drawLayersInternal( // if the layer's buffer has a fence, then we must must respect the fence prior to using // the buffer. - if (layer.source.buffer.fence != nullptr) { - waitFence(layer.source.buffer.fence->get()); + if (layer->source.buffer.fence != nullptr) { + waitFence(layer->source.buffer.fence->get()); } // isOpaque means we need to ignore the alpha in the image, @@ -1050,7 +1051,7 @@ void SkiaGLRenderEngine::drawLayersInternal( sk_sp shader; - if (layer.source.buffer.useTextureFiltering) { + if (layer->source.buffer.useTextureFiltering) { shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions( {SkFilterMode::kLinear, SkMipmapMode::kNone}), @@ -1068,21 +1069,21 @@ void SkiaGLRenderEngine::drawLayersInternal( paint.setShader(createRuntimeEffectShader(shader, layer, display, !item.isOpaque && item.usePremultipliedAlpha, requiresLinearEffect)); - paint.setAlphaf(layer.alpha); + paint.setAlphaf(layer->alpha); } else { ATRACE_NAME("DrawColor"); - const auto color = layer.source.solidColor; + const auto color = layer->source.solidColor; sk_sp shader = SkShaders::Color(SkColor4f{.fR = color.r, .fG = color.g, .fB = color.b, - .fA = layer.alpha}, + .fA = layer->alpha}, toSkColorSpace(layerDataspace)); paint.setShader(createRuntimeEffectShader(shader, layer, display, /* undoPremultipliedAlpha */ false, requiresLinearEffect)); } - if (layer.disableBlending) { + if (layer->disableBlending) { paint.setBlendMode(SkBlendMode::kSrc); } @@ -1250,13 +1251,13 @@ inline std::pair SkiaGLRenderEngine::getBoundsAndClip(const Fl return {SkRRect::MakeRect(bounds), clip}; } -inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings& layer, +inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings* layer, bool colorTransformModifiesAlpha) { - if (layer.backgroundBlurRadius > 0 || layer.blurRegions.size()) { + if (layer->backgroundBlurRadius > 0 || layer->blurRegions.size()) { // return false if the content is opaque and would therefore occlude the blur - const bool opaqueContent = !layer.source.buffer.buffer || layer.source.buffer.isOpaque; - const bool opaqueAlpha = layer.alpha == 1.0f && !colorTransformModifiesAlpha; - return layer.skipContentDraw || !(opaqueContent && opaqueAlpha); + const bool opaqueContent = !layer->source.buffer.buffer || layer->source.buffer.isOpaque; + const bool opaqueAlpha = layer->alpha == 1.0f && !colorTransformModifiesAlpha; + return layer->skipContentDraw || !(opaqueContent && opaqueAlpha); } return false; } diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 74ce6513e9..e010c35c13 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -74,7 +74,7 @@ protected: bool canSkipPostRenderCleanup() const override; void drawLayersInternal(const std::shared_ptr>&& resultPromise, const DisplaySettings& display, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override; @@ -92,7 +92,7 @@ private: inline SkRect getSkRect(const Rect& layer); inline std::pair getBoundsAndClip(const FloatRect& bounds, const FloatRect& crop, float cornerRadius); - inline bool layerHasBlur(const LayerSettings& layer, bool colorTransformModifiesAlpha); + inline bool layerHasBlur(const LayerSettings* layer, bool colorTransformModifiesAlpha); inline SkColor getSkColor(const vec4& color); inline SkM44 getSkM44(const mat4& matrix); inline SkPoint3 getSkPoint3(const vec3& vector); @@ -108,7 +108,8 @@ private: const ShadowSettings& shadowSettings); // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned. // Otherwise it returns the input shader. - sk_sp createRuntimeEffectShader(sk_sp shader, const LayerSettings& layer, + sk_sp createRuntimeEffectShader(sk_sp shader, + const LayerSettings* layer, const DisplaySettings& display, bool undoPremultipliedAlpha, bool requiresLinearEffect); diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index eb65e83324..f61653b940 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -55,7 +55,7 @@ protected: virtual void drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override { resultPromise->set_value({NO_ERROR, base::unique_fd()}); diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index c2c05f41b7..694bda65d4 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -417,11 +417,10 @@ public: DEFAULT_DISPLAY_HEIGHT - DEFAULT_DISPLAY_OFFSET); } - void invokeDraw(const renderengine::DisplaySettings& settings, - const std::vector& layers) { + void invokeDraw(renderengine::DisplaySettings settings, + std::vector layers) { std::future result = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd()); - ASSERT_TRUE(result.valid()); auto [status, fence] = result.get(); @@ -437,7 +436,7 @@ public: void drawEmptyLayers() { renderengine::DisplaySettings settings; - std::vector layers; + std::vector layers; invokeDraw(settings, layers); } @@ -630,7 +629,7 @@ void RenderEngineTest::fillBuffer(half r, half g, half b, half a) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -638,7 +637,7 @@ void RenderEngineTest::fillBuffer(half r, half g, half b, half a) { SourceVariant::fillColor(layer, r, g, b, this); layer.alpha = a; - layers.push_back(layer); + layers.push_back(&layer); invokeDraw(settings, layers); } @@ -674,7 +673,7 @@ void RenderEngineTest::fillRedOffsetBuffer() { settings.physicalDisplay = offsetRect(); settings.clip = offsetRectAtZero(); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -682,7 +681,7 @@ void RenderEngineTest::fillRedOffsetBuffer() { SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0f; - layers.push_back(layer); + layers.push_back(&layer); invokeDraw(settings, layers); } @@ -709,7 +708,7 @@ void RenderEngineTest::fillBufferCheckers(uint32_t orientationFlag) { settings.clip = Rect(2, 2); settings.orientation = orientationFlag; - std::vector layers; + std::vector layers; renderengine::LayerSettings layerOne; layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -732,9 +731,9 @@ void RenderEngineTest::fillBufferCheckers(uint32_t orientationFlag) { SourceVariant::fillColor(layerThree, 0.0f, 0.0f, 1.0f, this); layerThree.alpha = 1.0f; - layers.push_back(layerOne); - layers.push_back(layerTwo); - layers.push_back(layerThree); + layers.push_back(&layerOne); + layers.push_back(&layerTwo); + layers.push_back(&layerThree); invokeDraw(settings, layers); } @@ -811,7 +810,7 @@ void RenderEngineTest::fillBufferWithLayerTransform() { settings.clip = Rect(2, 2); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -822,7 +821,7 @@ void RenderEngineTest::fillBufferWithLayerTransform() { layer.source.solidColor = half3(1.0f, 0.0f, 0.0f); layer.alpha = 1.0f; - layers.push_back(layer); + layers.push_back(&layer); invokeDraw(settings, layers); } @@ -844,7 +843,7 @@ void RenderEngineTest::fillBufferWithColorTransform() { settings.clip = Rect(1, 1); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -861,7 +860,7 @@ void RenderEngineTest::fillBufferWithColorTransform() { layer.alpha = 1.0f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(layer); + layers.push_back(&layer); invokeDraw(settings, layers); } @@ -878,7 +877,7 @@ void RenderEngineTest::fillBufferWithColorTransformZeroLayerAlpha() { settings.physicalDisplay = fullscreenRect(); settings.clip = Rect(1, 1); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); @@ -891,7 +890,7 @@ void RenderEngineTest::fillBufferWithColorTransformZeroLayerAlpha() { layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(layer); + layers.push_back(&layer); invokeDraw(settings, layers); } @@ -909,7 +908,7 @@ void RenderEngineTest::fillRedBufferWithRoundedCorners() { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -919,7 +918,7 @@ void RenderEngineTest::fillRedBufferWithRoundedCorners() { SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0f; - layers.push_back(layer); + layers.push_back(&layer); invokeDraw(settings, layers); } @@ -950,14 +949,14 @@ void RenderEngineTest::fillBufferAndBlurBackground() { settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; renderengine::LayerSettings backgroundLayer; backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect(); SourceVariant::fillColor(backgroundLayer, 0.0f, 1.0f, 0.0f, this); backgroundLayer.alpha = 1.0f; - layers.emplace_back(backgroundLayer); + layers.push_back(&backgroundLayer); renderengine::LayerSettings leftLayer; leftLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -965,7 +964,7 @@ void RenderEngineTest::fillBufferAndBlurBackground() { Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT).toFloatRect(); SourceVariant::fillColor(leftLayer, 1.0f, 0.0f, 0.0f, this); leftLayer.alpha = 1.0f; - layers.emplace_back(leftLayer); + layers.push_back(&leftLayer); renderengine::LayerSettings blurLayer; blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -973,7 +972,7 @@ void RenderEngineTest::fillBufferAndBlurBackground() { blurLayer.backgroundBlurRadius = blurRadius; SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this); blurLayer.alpha = 0; - layers.emplace_back(blurLayer); + layers.push_back(&blurLayer); invokeDraw(settings, layers); @@ -995,14 +994,14 @@ void RenderEngineTest::fillSmallLayerAndBlurBackground() { settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; renderengine::LayerSettings backgroundLayer; backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect(); SourceVariant::fillColor(backgroundLayer, 1.0f, 0.0f, 0.0f, this); backgroundLayer.alpha = 1.0f; - layers.push_back(backgroundLayer); + layers.push_back(&backgroundLayer); renderengine::LayerSettings blurLayer; blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1010,7 +1009,7 @@ void RenderEngineTest::fillSmallLayerAndBlurBackground() { blurLayer.backgroundBlurRadius = blurRadius; SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this); blurLayer.alpha = 0; - layers.push_back(blurLayer); + layers.push_back(&blurLayer); invokeDraw(settings, layers); @@ -1027,7 +1026,7 @@ void RenderEngineTest::overlayCorners() { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layersFirst; + std::vector layersFirst; renderengine::LayerSettings layerOne; layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1036,14 +1035,14 @@ void RenderEngineTest::overlayCorners() { SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this); layerOne.alpha = 0.2; - layersFirst.push_back(layerOne); + layersFirst.push_back(&layerOne); invokeDraw(settings, layersFirst); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 0); - std::vector layersSecond; + std::vector layersSecond; renderengine::LayerSettings layerTwo; layerTwo.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; layerTwo.geometry.boundaries = @@ -1052,7 +1051,7 @@ void RenderEngineTest::overlayCorners() { SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this); layerTwo.alpha = 1.0f; - layersSecond.push_back(layerTwo); + layersSecond.push_back(&layerTwo); invokeDraw(settings, layersSecond); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0); @@ -1067,7 +1066,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() { settings.clip = Rect(1, 1); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1103,7 +1102,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() { layer.alpha = 1.0f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(layer); + layers.push_back(&layer); invokeDraw(settings, layers); } @@ -1119,7 +1118,7 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() { // Here logical space is 1x1 settings.clip = Rect(1, 1); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; const auto buf = allocateSourceBuffer(1, 1); @@ -1142,7 +1141,7 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() { layer.alpha = 0.5f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(layer); + layers.push_back(&layer); invokeDraw(settings, layers); } @@ -1158,7 +1157,7 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() { // Here logical space is 1x1 settings.clip = Rect(1, 1); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; const auto buf = allocateSourceBuffer(1, 1); @@ -1181,7 +1180,7 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() { layer.alpha = 0.5f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(layer); + layers.push_back(&layer); invokeDraw(settings, layers); } @@ -1200,7 +1199,7 @@ void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLaye settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; // add background layer renderengine::LayerSettings bgLayer; @@ -1209,7 +1208,7 @@ void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLaye ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f, backgroundColor.b / 255.0f, this); bgLayer.alpha = backgroundColor.a / 255.0f; - layers.push_back(bgLayer); + layers.push_back(&bgLayer); // add shadow layer renderengine::LayerSettings shadowLayer; @@ -1217,14 +1216,14 @@ void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLaye shadowLayer.geometry.boundaries = castingLayer.geometry.boundaries; shadowLayer.alpha = castingLayer.alpha; shadowLayer.shadow = shadow; - layers.push_back(shadowLayer); + layers.push_back(&shadowLayer); // add layer casting the shadow renderengine::LayerSettings layer = castingLayer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; SourceVariant::fillColor(layer, casterColor.r / 255.0f, casterColor.g / 255.0f, casterColor.b / 255.0f, this); - layers.push_back(layer); + layers.push_back(&layer); invokeDraw(settings, layers); } @@ -1237,7 +1236,7 @@ void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds, settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; // add background layer renderengine::LayerSettings bgLayer; @@ -1246,7 +1245,7 @@ void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds, ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f, backgroundColor.b / 255.0f, this); bgLayer.alpha = backgroundColor.a / 255.0f; - layers.push_back(bgLayer); + layers.push_back(&bgLayer); // add shadow layer renderengine::LayerSettings shadowLayer; @@ -1256,7 +1255,7 @@ void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds, shadowLayer.alpha = 1.0f; ColorSourceVariant::fillColor(shadowLayer, 0, 0, 0, this); shadowLayer.shadow = shadow; - layers.push_back(shadowLayer); + layers.push_back(&shadowLayer); invokeDraw(settings, layers); } @@ -1292,8 +1291,8 @@ TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) { // Transform the red color. bgLayer.colorTransform = mat4(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - std::vector layers; - layers.push_back(bgLayer); + std::vector layers; + layers.push_back(&bgLayer); invokeDraw(settings, layers); @@ -1307,11 +1306,11 @@ TEST_P(RenderEngineTest, drawLayers_nullOutputBuffer) { renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + 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); + layers.push_back(&layer); std::future result = mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd()); @@ -1336,12 +1335,12 @@ TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) { settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = fullscreenRect().toFloatRect(); BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0; - layers.push_back(layer); + layers.push_back(&layer); std::future result = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd()); @@ -1744,12 +1743,12 @@ TEST_P(RenderEngineTest, cleanupPostRender_cleansUpOnce) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = fullscreenRect().toFloatRect(); BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0; - layers.push_back(layer); + layers.push_back(&layer); std::future resultOne = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd()); @@ -1780,7 +1779,7 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1791,7 +1790,7 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); redLayer.alpha = 1.0f; - layers.push_back(redLayer); + layers.push_back(&redLayer); // Green layer with 1/3 size. renderengine::LayerSettings greenLayer; @@ -1806,7 +1805,7 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f); greenLayer.alpha = 1.0f; - layers.push_back(greenLayer); + layers.push_back(&greenLayer); invokeDraw(settings, layers); @@ -1829,7 +1828,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1840,7 +1839,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); redLayer.alpha = 1.0f; - layers.push_back(redLayer); + layers.push_back(&redLayer); // Green layer with 1/2 size with parent crop rect. renderengine::LayerSettings greenLayer = redLayer; @@ -1848,7 +1847,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT / 2); greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f); - layers.push_back(greenLayer); + layers.push_back(&greenLayer); invokeDraw(settings, layers); @@ -1874,7 +1873,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1885,7 +1884,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) { redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); redLayer.alpha = 1.0f; - layers.push_back(redLayer); + layers.push_back(&redLayer); invokeDraw(settings, layers); // Due to roundedCornersRadius, the top corners are untouched. @@ -1924,7 +1923,7 @@ TEST_P(RenderEngineTest, testClear) { .disableBlending = true, }; - std::vector layers{redLayer, clearLayer}; + std::vector layers{&redLayer, &clearLayer}; invokeDraw(display, layers); expectBufferColor(rect, 0, 0, 0, 0); } @@ -1972,7 +1971,7 @@ TEST_P(RenderEngineTest, testDisableBlendingBuffer) { .disableBlending = true, }; - std::vector layers{redLayer, greenLayer}; + std::vector layers{&redLayer, &greenLayer}; invokeDraw(display, layers); expectBufferColor(rect, 0, 128, 0, 128); } @@ -2018,7 +2017,7 @@ TEST_P(RenderEngineTest, test_isOpaque) { .alpha = 1.0f, }; - std::vector layers{greenLayer}; + std::vector layers{&greenLayer}; invokeDraw(display, layers); if (GetParam()->useColorManagement()) { diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index db7e12b71b..99250c1412 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -172,21 +172,20 @@ TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsTrue) { TEST_F(RenderEngineThreadedTest, drawLayers) { renderengine::DisplaySettings settings; - std::vector layers; + std::vector layers; std::shared_ptr buffer = std::make_shared< renderengine::ExternalTexture>(new GraphicBuffer(), *mRenderEngine, renderengine::ExternalTexture::Usage::READABLE | renderengine::ExternalTexture::Usage::WRITEABLE); - base::unique_fd bufferFence; EXPECT_CALL(*mRenderEngine, drawLayersInternal) .WillOnce([&](const std::shared_ptr>&& resultPromise, const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd&&) -> void { + base::unique_fd &&) -> void { resultPromise->set_value({NO_ERROR, base::unique_fd()}); }); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index 3d446e8e72..a549672259 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -306,7 +306,7 @@ bool RenderEngineThreaded::canSkipPostRenderCleanup() const { void RenderEngineThreaded::drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { resultPromise->set_value({NO_ERROR, base::unique_fd()}); @@ -314,20 +314,19 @@ void RenderEngineThreaded::drawLayersInternal( } std::future RenderEngineThreaded::drawLayers( - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { ATRACE_CALL(); const auto resultPromise = std::make_shared>(); std::future resultFuture = resultPromise->get_future(); - int fd = bufferFence.release(); { std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([resultPromise, display, layers, buffer, useFramebufferCache, - fd](renderengine::RenderEngine& instance) { + mFunctionCalls.push([resultPromise, &display, &layers, &buffer, useFramebufferCache, + &bufferFence](renderengine::RenderEngine& instance) { ATRACE_NAME("REThreaded::drawLayers"); instance.drawLayersInternal(std::move(resultPromise), display, layers, buffer, - useFramebufferCache, base::unique_fd(fd)); + useFramebufferCache, std::move(bufferFence)); }); } mCondition.notify_one(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 0159cfaece..2303caa7eb 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -57,7 +57,7 @@ public: void cleanupPostRender() override; std::future drawLayers(const DisplaySettings& display, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override; @@ -73,7 +73,7 @@ protected: bool canSkipPostRenderCleanup() const override; void drawLayersInternal(const std::shared_ptr>&& resultPromise, const DisplaySettings& display, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 6c60e53841..f98681e1ce 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -48,9 +48,7 @@ BufferQueueLayer::~BufferQueueLayer() { // Interface implementation for Layer // ----------------------------------------------------------------------- -void BufferQueueLayer::onLayerDisplayed( - std::shared_future futureRenderEngineResult) { - sp releaseFence = new Fence(dup(futureRenderEngineResult.get().drawFence)); +void BufferQueueLayer::onLayerDisplayed(const sp& releaseFence) { mConsumer->setReleaseFence(releaseFence); // Prevent tracing the same release multiple times. diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index dfdb5c055d..a3bd725cfe 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -42,8 +42,7 @@ public: // Implements Layer. const char* getType() const override { return "BufferQueueLayer"; } - void onLayerDisplayed( - std::shared_future futureRenderEngineResult) override; + void onLayerDisplayed(const sp& releaseFence) override; // If a buffer was replaced this frame, release the former buffer void releasePendingBuffer(nsecs_t dequeueReadyTime) override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 454363ac3f..132ee9d71b 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -70,11 +70,69 @@ BufferStateLayer::~BufferStateLayer() { } } +status_t BufferStateLayer::addReleaseFence(const sp& ch, + const sp& fence) { + if (ch == nullptr) { + return OK; + } + ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; + if (!ch->previousReleaseFence.get()) { + ch->previousReleaseFence = fence; + return OK; + } + + // Below logic is lifted from ConsumerBase.cpp: + // Check status of fences first because merging is expensive. + // Merging an invalid fence with any other fence results in an + // invalid fence. + auto currentStatus = ch->previousReleaseFence->getStatus(); + if (currentStatus == Fence::Status::Invalid) { + ALOGE("Existing fence has invalid state, layer: %s", mName.c_str()); + return BAD_VALUE; + } + + auto incomingStatus = fence->getStatus(); + if (incomingStatus == Fence::Status::Invalid) { + ALOGE("New fence has invalid state, layer: %s", mName.c_str()); + ch->previousReleaseFence = fence; + return BAD_VALUE; + } + + // If both fences are signaled or both are unsignaled, we need to merge + // them to get an accurate timestamp. + if (currentStatus == incomingStatus) { + char fenceName[32] = {}; + snprintf(fenceName, 32, "%.28s", mName.c_str()); + sp mergedFence = Fence::merge( + fenceName, ch->previousReleaseFence, fence); + if (!mergedFence.get()) { + ALOGE("failed to merge release fences, layer: %s", mName.c_str()); + // synchronization is broken, the best we can do is hope fences + // signal in order so the new fence will act like a union + ch->previousReleaseFence = fence; + return BAD_VALUE; + } + ch->previousReleaseFence = mergedFence; + } else if (incomingStatus == Fence::Status::Unsignaled) { + // If one fence has signaled and the other hasn't, the unsignaled + // fence will approximately correspond with the correct timestamp. + // There's a small race if both fences signal at about the same time + // and their statuses are retrieved with unfortunate timing. However, + // by this point, they will have both signaled and only the timestamp + // will be slightly off; any dependencies after this point will + // already have been met. + ch->previousReleaseFence = fence; + } + // else if (currentStatus == Fence::Status::Unsignaled) is a no-op. + + return OK; +} + // ----------------------------------------------------------------------- // Interface implementation for Layer // ----------------------------------------------------------------------- -void BufferStateLayer::onLayerDisplayed( - std::shared_future futureRenderEngineResult) { +void BufferStateLayer::onLayerDisplayed(const sp& releaseFence) { + // If a layer has been displayed again we may need to clear // the mLastClientComposition fence that we use for early release in setBuffer // (as we now have a new fence which won't pass through the client composition path in some cases @@ -88,6 +146,9 @@ void BufferStateLayer::onLayerDisplayed( mLastClientCompositionDisplayed = true; } + if (!releaseFence->isValid()) { + return; + } // The previous release fence notifies the client that SurfaceFlinger is done with the previous // buffer that was presented on this layer. The first transaction that came in this frame that // replaced the previous buffer on this layer needs this release fence, because the fence will @@ -112,19 +173,17 @@ void BufferStateLayer::onLayerDisplayed( break; } } + auto status = addReleaseFence(ch, releaseFence); + if (status != OK) { + ALOGE("Failed to add release fence for layer %s", getName().c_str()); + } - mListPreviousReleaseFences.emplace_back(futureRenderEngineResult); + mPreviousReleaseFence = releaseFence; // Prevent tracing the same release multiple times. if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) { mPreviousReleasedFrameNumber = mPreviousFrameNumber; } - - if (ch != nullptr) { - ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; - ch->previousReleaseFences.emplace_back(futureRenderEngineResult); - ch->name = mName; - } } void BufferStateLayer::onSurfaceFrameCreated( @@ -172,18 +231,9 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { mFlinger->getTransactionCallbackInvoker().addCallbackHandles( mDrawingState.callbackHandles, jankData); - sp releaseFence = Fence::NO_FENCE; - for (auto& handle : mDrawingState.callbackHandles) { - if (handle->releasePreviousBuffer && - mDrawingState.releaseBufferEndpoint == handle->listener) { - releaseFence = - handle->previousReleaseFence ? handle->previousReleaseFence : Fence::NO_FENCE; - break; - } - } - mDrawingState.callbackHandles = {}; + const sp& releaseFence(mPreviousReleaseFence); std::shared_ptr releaseFenceTime = std::make_shared(releaseFence); { Mutex::Autolock lock(mFrameEventHistoryMutex); diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 6cb9b352f8..87b68ea71b 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -39,9 +39,7 @@ public: // Implements Layer. const char* getType() const override { return "BufferStateLayer"; } - void onLayerDisplayed( - std::shared_future futureRenderEngineResult) override; - + void onLayerDisplayed(const sp& releaseFence) override; void releasePendingBuffer(nsecs_t dequeueReadyTime) override; void finalizeFrameEventHistory(const std::shared_ptr& glDoneFence, @@ -117,6 +115,8 @@ private: bool updateFrameEventHistory(const sp& acquireFence, nsecs_t postedTime, nsecs_t requestedPresentTime); + status_t addReleaseFence(const sp& ch, const sp& releaseFence); + bool latchSidebandStream(bool& recomputeVisibleRegions) override; bool hasFrameUpdate() const override; @@ -139,7 +139,7 @@ private: std::shared_ptr getBufferFromBufferData( const BufferData& bufferData); - std::vector> mListPreviousReleaseFences; + sp mPreviousReleaseFence; ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; uint64_t mPreviousReleasedFrameNumber = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index ac243c0a17..f7b71cf9fe 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -16,7 +16,6 @@ #pragma once -#include #include #include #include @@ -27,7 +26,6 @@ #pragma clang diagnostic ignored "-Wextra" #include -#include // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" @@ -153,7 +151,7 @@ public: ClientCompositionTargetSettings&) = 0; // Called after the layer is displayed to update the presentation fence - virtual void onLayerDisplayed(std::shared_future) = 0; + virtual void onLayerDisplayed(const sp&) = 0; // Gets some kind of identifier for the layer for debug purposes. virtual const char* getDebugName() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index 16aebef9f3..d215bda891 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -39,7 +39,7 @@ public: std::vector( compositionengine::LayerFE::ClientCompositionTargetSettings&)); - MOCK_METHOD1(onLayerDisplayed, void(std::shared_future)); + MOCK_METHOD1(onLayerDisplayed, void(const sp&)); MOCK_CONST_METHOD0(getDebugName, const char*()); MOCK_CONST_METHOD0(getSequence, int32_t()); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 7ea1aa2f92..048d7c2b4a 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include @@ -1098,12 +1097,12 @@ std::optional Output::composeSurfaces( setExpensiveRenderingExpected(true); } - std::vector clientRenderEngineLayers; - clientRenderEngineLayers.reserve(clientCompositionLayers.size()); + std::vector clientCompositionLayerPointers; + clientCompositionLayerPointers.reserve(clientCompositionLayers.size()); std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(), - std::back_inserter(clientRenderEngineLayers), - [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings { - return settings; + std::back_inserter(clientCompositionLayerPointers), + [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings* { + return &settings; }); const nsecs_t renderEngineStart = systemTime(); @@ -1116,7 +1115,7 @@ std::optional Output::composeSurfaces( const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay; auto [status, drawFence] = renderEngine - .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, tex, + .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex, useFramebufferCache, std::move(fd)) .get(); @@ -1296,10 +1295,8 @@ void Output::postFramebuffer() { releaseFence = Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence); } - layer->getLayerFE().onLayerDisplayed( - ftl::yield( - {NO_ERROR, base::unique_fd(releaseFence->dup())}) - .share()); + + layer->getLayerFE().onLayerDisplayed(releaseFence); } // We've got a list of layers needing fences, that are disjoint with @@ -1307,9 +1304,7 @@ void Output::postFramebuffer() { // supply them with the present fence. for (auto& weakLayer : mReleasedLayers) { if (auto layer = weakLayer.promote(); layer != nullptr) { - layer->onLayerDisplayed(ftl::yield( - {NO_ERROR, base::unique_fd(frame.presentFence->dup())}) - .share()); + layer->onLayerDisplayed(frame.presentFence); } } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index ec52e59ab0..e6b716e8f2 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -193,6 +193,11 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te clientCompositionList.cend()); } + std::vector layerSettingsPointers; + std::transform(layerSettings.cbegin(), layerSettings.cend(), + std::back_inserter(layerSettingsPointers), + [](const renderengine::LayerSettings& settings) { return &settings; }); + renderengine::LayerSettings blurLayerSettings; if (mBlurLayer) { auto blurSettings = targetSettings; @@ -207,7 +212,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te blurLayerSettings.name = std::string("blur layer"); // Clear out the shadow settings blurLayerSettings.shadow = {}; - layerSettings.push_back(blurLayerSettings); + layerSettingsPointers.push_back(&blurLayerSettings); } renderengine::LayerSettings holePunchSettings; @@ -225,7 +230,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te holePunchSettings.disableBlending = true; holePunchSettings.alpha = 0.0f; holePunchSettings.name = std::string("hole punch layer"); - layerSettings.push_back(holePunchSettings); + layerSettingsPointers.push_back(&holePunchSettings); // Add a solid background as the first layer in case there is no opaque // buffer behind the punch hole @@ -234,7 +239,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te holePunchBackgroundSettings.geometry.boundaries = holePunchSettings.geometry.boundaries; holePunchBackgroundSettings.geometry.positionTransform = holePunchSettings.geometry.positionTransform; - layerSettings.emplace(layerSettings.begin(), holePunchBackgroundSettings); + layerSettingsPointers.insert(layerSettingsPointers.begin(), &holePunchBackgroundSettings); } if (sDebugHighlighLayers) { @@ -252,7 +257,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te .alpha = half(0.05f), }; - layerSettings.emplace_back(highlight); + layerSettingsPointers.emplace_back(&highlight); } auto texture = texturePool.borrowTexture(); @@ -268,8 +273,8 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te } auto [status, drawFence] = renderEngine - .drawLayers(displaySettings, layerSettings, texture->get(), - false, std::move(bufferFence)) + .drawLayers(displaySettings, layerSettingsPointers, + texture->get(), false, std::move(bufferFence)) .get(); if (status == NO_ERROR) { diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index cf63ef5183..8f0028c399 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -2885,24 +2884,12 @@ TEST_F(OutputPostFramebufferTest, releaseFencesAreSentToLayerFE) { // are passed. This happens to work with the current implementation, but // would not survive certain calls like Fence::merge() which would return a // new instance. - base::unique_fd layer1FD(layer1Fence->dup()); - base::unique_fd layer2FD(layer2Fence->dup()); - base::unique_fd layer3FD(layer3Fence->dup()); - EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_)) - .WillOnce([&layer1FD](std::shared_future - futureRenderEngineResult) { - EXPECT_EQ(layer1FD, futureRenderEngineResult.get().drawFence); - }); - EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_)) - .WillOnce([&layer2FD](std::shared_future - futureRenderEngineResult) { - EXPECT_EQ(layer2FD, futureRenderEngineResult.get().drawFence); - }); - EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_)) - .WillOnce([&layer3FD](std::shared_future - futureRenderEngineResult) { - EXPECT_EQ(layer3FD, futureRenderEngineResult.get().drawFence); - }); + EXPECT_CALL(*mLayer1.layerFE, + onLayerDisplayed(Property(&sp::get, Eq(layer1Fence.get())))); + EXPECT_CALL(*mLayer2.layerFE, + onLayerDisplayed(Property(&sp::get, Eq(layer2Fence.get())))); + EXPECT_CALL(*mLayer3.layerFE, + onLayerDisplayed(Property(&sp::get, Eq(layer3Fence.get())))); mOutput.postFramebuffer(); } @@ -2928,9 +2915,9 @@ TEST_F(OutputPostFramebufferTest, releaseFencesIncludeClientTargetAcquireFence) // Fence::merge is called, and since none of the fences are actually valid, // Fence::NO_FENCE is returned and passed to each onLayerDisplayed() call. // This is the best we can do without creating a real kernel fence object. - EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed).WillOnce(Return()); - EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed).WillOnce(Return()); - EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed).WillOnce(Return()); + EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(Fence::NO_FENCE)); + EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(Fence::NO_FENCE)); + EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(Fence::NO_FENCE)); mOutput.postFramebuffer(); } @@ -2962,22 +2949,12 @@ TEST_F(OutputPostFramebufferTest, releasedLayersSentPresentFence) { EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted()); // Each released layer should be given the presentFence. - base::unique_fd layerFD(presentFence.get()->dup()); - EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_)) - .WillOnce([&layerFD](std::shared_future - futureRenderEngineResult) { - EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence); - }); - EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_)) - .WillOnce([&layerFD](std::shared_future - futureRenderEngineResult) { - EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence); - }); - EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_)) - .WillOnce([&layerFD](std::shared_future - futureRenderEngineResult) { - EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence); - }); + EXPECT_CALL(*releasedLayer1, + onLayerDisplayed(Property(&sp::get, Eq(presentFence.get())))); + EXPECT_CALL(*releasedLayer2, + onLayerDisplayed(Property(&sp::get, Eq(presentFence.get())))); + EXPECT_CALL(*releasedLayer3, + onLayerDisplayed(Property(&sp::get, Eq(presentFence.get())))); mOutput.postFramebuffer(); @@ -3154,9 +3131,9 @@ TEST_F(OutputComposeSurfacesTest, handlesZeroCompositionRequests) { EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); EXPECT_CALL(mRenderEngine, drawLayers(_, IsEmpty(), _, false, _)) .WillRepeatedly([&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd&&) + base::unique_fd &&) -> std::future { return futureOf({NO_ERROR, base::unique_fd()}); }); @@ -3184,11 +3161,11 @@ TEST_F(OutputComposeSurfacesTest, buildsAndRendersRequestList) { })); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) .WillRepeatedly([&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd&&) + base::unique_fd &&) -> std::future { return futureOf({NO_ERROR, base::unique_fd()}); }); @@ -3219,11 +3196,11 @@ TEST_F(OutputComposeSurfacesTest, })); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, true, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _)) .WillRepeatedly([&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd&&) + base::unique_fd &&) -> std::future { return futureOf({NO_ERROR, base::unique_fd()}); }); @@ -3249,7 +3226,7 @@ TEST_F(OutputComposeSurfacesTest, renderDuplicateClientCompositionRequestsWithou .WillRepeatedly(Return()); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) .Times(2) .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))) @@ -3281,7 +3258,7 @@ TEST_F(OutputComposeSurfacesTest, skipDuplicateClientCompositionRequests) { .WillRepeatedly(Return()); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false)); @@ -3317,11 +3294,11 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) { EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)) .WillOnce(Return(mOutputBuffer)) .WillOnce(Return(otherOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) .WillRepeatedly([&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd&&) + base::unique_fd &&) -> std::future { return futureOf({NO_ERROR, base::unique_fd()}); }); @@ -3353,10 +3330,10 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfRequestChanges) { .WillRepeatedly(Return()); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r3), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, false, _)) .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); @@ -3510,9 +3487,9 @@ struct OutputComposeSurfacesTest_HandlesProtectedContent : public OutputComposeS EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _)) .WillRepeatedly( [&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd&&) -> std::future { + base::unique_fd &&) -> std::future { return futureOf( {NO_ERROR, base::unique_fd()}); }); diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index 42b3d972a8..ecb05f8e5f 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -346,15 +346,15 @@ TEST_F(CachedSetTest, renderUnsecureOutput) { const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd&&) -> std::future { + base::unique_fd &&) -> std::future { EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()), displaySettings.orientation); - EXPECT_EQ(0.5f, layers[0].alpha); - EXPECT_EQ(0.75f, layers[1].alpha); + EXPECT_EQ(0.5f, layers[0]->alpha); + EXPECT_EQ(0.75f, layers[1]->alpha); EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace); return futureOf({NO_ERROR, base::unique_fd()}); }; @@ -398,15 +398,15 @@ TEST_F(CachedSetTest, renderSecureOutput) { const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd&&) -> std::future { + base::unique_fd &&) -> std::future { EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()), displaySettings.orientation); - EXPECT_EQ(0.5f, layers[0].alpha); - EXPECT_EQ(0.75f, layers[1].alpha); + EXPECT_EQ(0.5f, layers[0]->alpha); + EXPECT_EQ(0.75f, layers[1]->alpha); EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace); return futureOf({NO_ERROR, base::unique_fd()}); @@ -453,15 +453,15 @@ TEST_F(CachedSetTest, rendersWithOffsetFramebufferContent) { const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd&&) -> std::future { + base::unique_fd &&) -> std::future { EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()), displaySettings.orientation); - EXPECT_EQ(0.5f, layers[0].alpha); - EXPECT_EQ(0.75f, layers[1].alpha); + EXPECT_EQ(0.5f, layers[0]->alpha); + EXPECT_EQ(0.75f, layers[1]->alpha); EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace); return futureOf({NO_ERROR, base::unique_fd()}); @@ -656,26 +656,26 @@ TEST_F(CachedSetTest, addHolePunch) { const auto drawLayers = [&](const renderengine::DisplaySettings&, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd&&) -> std::future { + base::unique_fd &&) -> std::future { // If the highlight layer is enabled, it will increase the size by 1. // We're interested in the third layer either way. EXPECT_GE(layers.size(), 4u); { - const auto holePunchSettings = layers[3]; - EXPECT_EQ(nullptr, holePunchSettings.source.buffer.buffer); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings.source.solidColor); - EXPECT_TRUE(holePunchSettings.disableBlending); - EXPECT_EQ(0.0f, holePunchSettings.alpha); + const auto* holePunchSettings = layers[3]; + EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor); + EXPECT_TRUE(holePunchSettings->disableBlending); + EXPECT_EQ(0.0f, holePunchSettings->alpha); } { - const auto holePunchBackgroundSettings = layers[0]; - EXPECT_EQ(nullptr, holePunchBackgroundSettings.source.buffer.buffer); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings.source.solidColor); - EXPECT_FALSE(holePunchBackgroundSettings.disableBlending); - EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha); + const auto* holePunchBackgroundSettings = layers[0]; + EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor); + EXPECT_FALSE(holePunchBackgroundSettings->disableBlending); + EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha); } return futureOf({NO_ERROR, base::unique_fd()}); @@ -717,27 +717,27 @@ TEST_F(CachedSetTest, addHolePunch_noBuffer) { const auto drawLayers = [&](const renderengine::DisplaySettings&, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd&&) -> std::future { + base::unique_fd &&) -> std::future { // If the highlight layer is enabled, it will increase the size by 1. // We're interested in the third layer either way. EXPECT_GE(layers.size(), 4u); { - const auto holePunchSettings = layers[3]; - EXPECT_EQ(nullptr, holePunchSettings.source.buffer.buffer); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings.source.solidColor); - EXPECT_TRUE(holePunchSettings.disableBlending); - EXPECT_EQ(0.0f, holePunchSettings.alpha); + const auto* holePunchSettings = layers[3]; + EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor); + EXPECT_TRUE(holePunchSettings->disableBlending); + EXPECT_EQ(0.0f, holePunchSettings->alpha); } { - const auto holePunchBackgroundSettings = layers[0]; - EXPECT_EQ(nullptr, holePunchBackgroundSettings.source.buffer.buffer); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings.source.solidColor); - EXPECT_FALSE(holePunchBackgroundSettings.disableBlending); - EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha); + const auto* holePunchBackgroundSettings = layers[0]; + EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor); + EXPECT_FALSE(holePunchBackgroundSettings->disableBlending); + EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha); } return futureOf({NO_ERROR, base::unique_fd()}); @@ -867,16 +867,16 @@ TEST_F(CachedSetTest, addBlur) { const auto drawLayers = [&](const renderengine::DisplaySettings&, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd&&) -> std::future { + base::unique_fd &&) -> std::future { // If the highlight layer is enabled, it will increase the size by 1. // We're interested in the third layer either way. EXPECT_GE(layers.size(), 3u); - const auto blurSettings = layers[2]; - EXPECT_TRUE(blurSettings.skipContentDraw); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings.source.solidColor); - EXPECT_EQ(0.0f, blurSettings.alpha); + const auto* blurSettings = layers[2]; + EXPECT_TRUE(blurSettings->skipContentDraw); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings->source.solidColor); + EXPECT_EQ(0.0f, blurSettings->alpha); return futureOf({NO_ERROR, base::unique_fd()}); }; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d68cf9720f..5707c67a56 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -221,8 +221,7 @@ LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp client, * Layer. So, the implementation is done in BufferLayer. When called on a * EffectLayer object, it's essentially a NOP. */ -void Layer::onLayerDisplayed( - std::shared_future /*futureRenderEngineResult*/) {} +void Layer::onLayerDisplayed(const sp& /*releaseFence*/) {} void Layer::removeRelativeZ(const std::vector& layersInTree) { if (mDrawingState.zOrderRelativeOf == nullptr) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4569f9af23..07b2eb5130 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -616,8 +616,7 @@ public: void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override; std::vector prepareClientCompositionList( compositionengine::LayerFE::ClientCompositionTargetSettings&) override; - void onLayerDisplayed( - std::shared_future futureRenderEngineResult) override; + void onLayerDisplayed(const sp& releaseFence) override; void setWasClientComposed(const sp& fence) override { mLastClientCompositionFence = fence; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index d0f56b5bdd..aa2fec56ad 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -356,13 +356,10 @@ void RegionSamplingThread::captureSample() { renderengine::ExternalTexture::Usage::WRITEABLE); } - auto captureScreenResultFuture = - mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - true /* regionSampling */, false /* grayscale */, nullptr); - auto& captureScreenResult = captureScreenResultFuture.get(); - if (captureScreenResult.drawFence.ok()) { - sync_wait(captureScreenResult.drawFence.get(), -1); - } + const sp captureListener = new SyncScreenCaptureListener(); + mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, + true /* regionSampling */, false /* grayscale */, captureListener); + ScreenCaptureResults captureResults = captureListener->waitForResults(); std::vector activeDescriptors; for (const auto& descriptor : descriptors) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 638458cfd3..acb81dc41c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5972,10 +5972,9 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, traverseLayersInLayerStack(layerStack, args.uid, visitor); }; - auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, - reqSize, args.pixelFormat, args.allowProtected, - args.grayscale, captureListener); - return captureResultFuture.get().status; + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, + args.pixelFormat, args.allowProtected, args.grayscale, + captureListener); } status_t SurfaceFlinger::captureDisplay(DisplayId displayId, @@ -6010,15 +6009,9 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId, traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor); }; - if (captureListener == nullptr) { - ALOGE("capture screen must provide a capture listener callback"); - return BAD_VALUE; - } - auto captureResultFuture = - captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, - ui::PixelFormat::RGBA_8888, false /* allowProtected */, - false /* grayscale */, captureListener); - return captureResultFuture.get().status; + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, + ui::PixelFormat::RGBA_8888, false /* allowProtected */, + false /* grayscale */, captureListener); } status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, @@ -6145,28 +6138,23 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, }); }; - if (captureListener == nullptr) { - ALOGE("capture screen must provide a capture listener callback"); - return BAD_VALUE; - } - - auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, - reqSize, args.pixelFormat, args.allowProtected, - args.grayscale, captureListener); - return captureResultFuture.get().status; + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, + args.pixelFormat, args.allowProtected, args.grayscale, + captureListener); } -std::shared_future SurfaceFlinger::captureScreenCommon( - RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, - ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale, - const sp& captureListener) { +status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, + TraverseLayersFunction traverseLayers, + ui::Size bufferSize, ui::PixelFormat reqPixelFormat, + bool allowProtected, bool grayscale, + const sp& captureListener) { ATRACE_CALL(); if (exceedsMaxRenderTargetSize(bufferSize.getWidth(), bufferSize.getHeight())) { ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32 ") that exceeds render target size limit.", bufferSize.getWidth(), bufferSize.getHeight()); - return ftl::yield({BAD_VALUE, base::unique_fd()}).share(); + return BAD_VALUE; } // Loop over all visible layers to see whether there's any protected layer. A protected layer is @@ -6206,23 +6194,25 @@ std::shared_future SurfaceFlinger::captureScre false /* regionSampling */, grayscale, captureListener); } -std::shared_future SurfaceFlinger::captureScreenCommon( +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) { + ALOGE("capture screen must provide a capture listener callback"); + return BAD_VALUE; + } + bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission(); - auto scheduleResultFuture = schedule([=, - renderAreaFuture = std::move(renderAreaFuture)]() mutable - -> std::shared_future { + static_cast(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable { if (mRefreshPending) { ALOGW("Skipping screenshot for now"); captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, regionSampling, grayscale, captureListener); - return ftl::yield({NO_ERROR, base::unique_fd()}) - .share(); + return; } ScreenCaptureResults captureResults; std::unique_ptr renderArea = renderAreaFuture.get(); @@ -6230,44 +6220,24 @@ std::shared_future SurfaceFlinger::captureScre ALOGW("Skipping screen capture because of invalid render area."); captureResults.result = NO_MEMORY; captureListener->onScreenCaptureCompleted(captureResults); - return ftl::yield({NO_ERROR, base::unique_fd()}) - .share(); + return; } - std::shared_future renderEngineResultFuture; - + status_t result = NO_ERROR; renderArea->render([&] { - renderEngineResultFuture = - renderScreenImplLocked(*renderArea, traverseLayers, buffer, - canCaptureBlackoutContent, regionSampling, grayscale, - captureResults); + result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, + canCaptureBlackoutContent, regionSampling, grayscale, + captureResults); }); - // spring up a thread to unblock SF main thread and wait for - // RenderEngineResult to be available - if (captureListener != nullptr) { - std::async([=]() mutable { - ATRACE_NAME("captureListener is nonnull!"); - auto& [status, drawFence] = renderEngineResultFuture.get(); - captureResults.result = status; - captureResults.fence = new Fence(dup(drawFence)); - captureListener->onScreenCaptureCompleted(captureResults); - }); - } - return renderEngineResultFuture; - }); - // flatten scheduleResultFuture object to single shared_future object - std::future captureScreenResultFuture = - ftl::chain(std::move(scheduleResultFuture)) - .then([=](std::shared_future futureObject) - -> renderengine::RenderEngineResult { - auto& [status, drawFence] = futureObject.get(); - return {status, base::unique_fd(dup(drawFence))}; - }); - return captureScreenResultFuture.share(); + captureResults.result = result; + captureListener->onScreenCaptureCompleted(captureResults); + })); + + return NO_ERROR; } -std::shared_future SurfaceFlinger::renderScreenImplLocked( +status_t SurfaceFlinger::renderScreenImplLocked( const RenderArea& renderArea, TraverseLayersFunction traverseLayers, const std::shared_ptr& buffer, bool canCaptureBlackoutContent, bool regionSampling, bool grayscale, @@ -6286,8 +6256,7 @@ std::shared_future SurfaceFlinger::renderScree // the impetus on WindowManager to not persist them. if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) { ALOGW("FB is protected: PERMISSION_DENIED"); - return ftl::yield({PERMISSION_DENIED, base::unique_fd()}) - .share(); + return PERMISSION_DENIED; } captureResults.buffer = buffer->getBuffer(); @@ -6369,12 +6338,11 @@ std::shared_future SurfaceFlinger::renderScree }); - std::vector clientRenderEngineLayers; - clientRenderEngineLayers.reserve(clientCompositionLayers.size()); + std::vector clientCompositionLayerPointers( + clientCompositionLayers.size()); std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(), - std::back_inserter(clientRenderEngineLayers), - [](compositionengine::LayerFE::LayerSettings& settings) - -> renderengine::LayerSettings { return settings; }); + clientCompositionLayerPointers.begin(), + std::pointer_traits::pointer_to); // Use an empty fence for the buffer fence, since we just created the buffer so // there is no need for synchronization with the GPU. @@ -6382,22 +6350,24 @@ std::shared_future SurfaceFlinger::renderScree getRenderEngine().useProtectedContext(useProtected); const constexpr bool kUseFramebufferCache = false; - std::future drawLayersResult = - getRenderEngine().drawLayers(clientCompositionDisplay, clientRenderEngineLayers, buffer, - kUseFramebufferCache, std::move(bufferFence)); - - std::shared_future drawLayersResultFuture = - drawLayersResult.share(); // drawLayersResult will be moved to shared one + auto [status, drawFence] = + getRenderEngine() + .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer, + kUseFramebufferCache, std::move(bufferFence)) + .get(); - for (auto* layer : renderedLayers) { - // make a copy of shared_future object for each layer - layer->onLayerDisplayed(drawLayersResultFuture); + if (drawFence >= 0) { + sp releaseFence = new Fence(dup(drawFence)); + for (auto* layer : renderedLayers) { + layer->onLayerDisplayed(releaseFence); + } } + captureResults.fence = new Fence(drawFence.release()); // Always switch back to unprotected context. getRenderEngine().useProtectedContext(false); - return drawLayersResultFuture; + return status; } void SurfaceFlinger::windowInfosReported() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 45fd94e50c..1f0e42ddf3 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -906,17 +906,17 @@ private: // Boot animation, on/off animations and screen capture void startBootAnim(); - std::shared_future captureScreenCommon( - RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, ui::PixelFormat, - bool allowProtected, bool grayscale, const sp&); - std::shared_future captureScreenCommon( - RenderAreaFuture, TraverseLayersFunction, - const std::shared_ptr&, bool regionSampling, - bool grayscale, const sp&); - std::shared_future renderScreenImplLocked( - const RenderArea&, TraverseLayersFunction, - const std::shared_ptr&, bool canCaptureBlackoutContent, - bool regionSampling, bool grayscale, ScreenCaptureResults&); + 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&, + bool regionSampling, bool grayscale, + const sp&); + status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction, + const std::shared_ptr&, + bool canCaptureBlackoutContent, bool regionSampling, + bool grayscale, ScreenCaptureResults&); // If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a // matching ownerUid diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index 8fbf0b4d07..c1eb8966d1 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -154,38 +154,6 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp& // destroyed the client side is dead and there won't be anyone to send the callback to. sp surfaceControl = handle->surfaceControl.promote(); if (surfaceControl) { - sp prevFence = nullptr; - - for (const auto& futureStruct : handle->previousReleaseFences) { - sp currentFence = sp::make(dup(futureStruct.get().drawFence)); - if (prevFence == nullptr && currentFence->getStatus() != Fence::Status::Invalid) { - prevFence = currentFence; - handle->previousReleaseFence = prevFence; - } else if (prevFence != nullptr) { - // If both fences are signaled or both are unsignaled, we need to merge - // them to get an accurate timestamp. - if (prevFence->getStatus() != Fence::Status::Invalid && - prevFence->getStatus() == currentFence->getStatus()) { - char fenceName[32] = {}; - snprintf(fenceName, 32, "%.28s", handle->name.c_str()); - sp mergedFence = Fence::merge(fenceName, prevFence, currentFence); - if (mergedFence->isValid()) { - handle->previousReleaseFence = mergedFence; - prevFence = handle->previousReleaseFence; - } - } else if (currentFence->getStatus() == Fence::Status::Unsignaled) { - // If one fence has signaled and the other hasn't, the unsignaled - // fence will approximately correspond with the correct timestamp. - // There's a small race if both fences signal at about the same time - // and their statuses are retrieved with unfortunate timing. However, - // by this point, they will have both signaled and only the timestamp - // will be slightly off; any dependencies after this point will - // already have been met. - handle->previousReleaseFence = currentFence; - } - } - } - handle->previousReleaseFences = {}; FrameEventHistoryStats eventStats(handle->frameNumber, handle->gpuCompositionDoneFence->getSnapshot().fence, handle->compositorTiming, handle->refreshStartTime, diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index 100dbfa8aa..7e879e119b 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -18,9 +18,8 @@ #include #include -#include -#include #include +#include #include #include #include @@ -29,7 +28,6 @@ #include #include -#include #include namespace android { @@ -44,9 +42,7 @@ public: wp surfaceControl; bool releasePreviousBuffer = false; - std::string name; sp previousReleaseFence; - std::vector> previousReleaseFences; nsecs_t acquireTime = -1; nsecs_t latchTime = -1; uint32_t transformHint = 0; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 61c7c398dd..5135ff952f 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -247,16 +247,10 @@ void CompositionTest::captureScreenComposition() { "screenshot"), *mRenderEngine, true); - auto result = mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer, - forSystem, regionSampling); - EXPECT_TRUE(result.valid()); - - auto& [status, drawFence] = result.get(); - - EXPECT_EQ(NO_ERROR, status); - if (drawFence.ok()) { - sync_wait(drawFence.get(), -1); - } + status_t result = + mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer, + forSystem, regionSampling); + EXPECT_EQ(NO_ERROR, result); LayerCase::cleanup(this); } @@ -352,9 +346,9 @@ struct BaseDisplayVariant { static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings, - const std::vector&, + const std::vector&, const std::shared_ptr&, - const bool, base::unique_fd&&) + const bool, base::unique_fd &&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), @@ -403,9 +397,9 @@ struct BaseDisplayVariant { Return(0))); EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings, - const std::vector&, + const std::vector&, const std::shared_ptr&, - const bool, base::unique_fd&&) + const bool, base::unique_fd &&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), @@ -639,9 +633,9 @@ struct BaseLayerProperties { static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layerSettings, + const std::vector& layerSettings, const std::shared_ptr&, const bool, - base::unique_fd&&) -> std::future { + base::unique_fd &&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -658,16 +652,16 @@ struct BaseLayerProperties { "verification lambda"; return resultFuture; } - const renderengine::LayerSettings layer = layerSettings.back(); - EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull())); - EXPECT_THAT(layer.source.buffer.fence, Not(IsNull())); - EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName); - EXPECT_EQ(false, layer.source.buffer.isY410BT2020); - EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha); - EXPECT_EQ(false, layer.source.buffer.isOpaque); - EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); - EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); - EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha); + const renderengine::LayerSettings* layer = layerSettings.back(); + EXPECT_THAT(layer->source.buffer.buffer, Not(IsNull())); + EXPECT_THAT(layer->source.buffer.fence, Not(IsNull())); + EXPECT_EQ(DEFAULT_TEXTURE_ID, layer->source.buffer.textureName); + EXPECT_EQ(false, layer->source.buffer.isY410BT2020); + EXPECT_EQ(true, layer->source.buffer.usePremultipliedAlpha); + EXPECT_EQ(false, layer->source.buffer.isOpaque); + EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius); + EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace); + EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha); return resultFuture; }); } @@ -691,9 +685,9 @@ struct BaseLayerProperties { static void setupREColorCompositionCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layerSettings, + const std::vector& layerSettings, const std::shared_ptr&, const bool, - base::unique_fd&&) -> std::future { + base::unique_fd &&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -710,14 +704,14 @@ struct BaseLayerProperties { "setupREColorCompositionCallExpectations verification lambda"; return resultFuture; } - const renderengine::LayerSettings layer = layerSettings.back(); - EXPECT_THAT(layer.source.buffer.buffer, IsNull()); + const renderengine::LayerSettings* layer = layerSettings.back(); + EXPECT_THAT(layer->source.buffer.buffer, IsNull()); EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1], LayerProperties::COLOR[2]), - layer.source.solidColor); - EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); - EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); - EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha); + layer->source.solidColor); + EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius); + EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace); + EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha); return resultFuture; }); } @@ -771,9 +765,9 @@ struct CommonSecureLayerProperties : public BaseLayerProperties static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layerSettings, + const std::vector& layerSettings, const std::shared_ptr&, const bool, - base::unique_fd&&) -> std::future { + base::unique_fd &&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -790,12 +784,12 @@ struct CommonSecureLayerProperties : public BaseLayerProperties "verification lambda"; return resultFuture; } - const renderengine::LayerSettings layer = layerSettings.back(); - EXPECT_THAT(layer.source.buffer.buffer, IsNull()); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor); - EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); - EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); - EXPECT_EQ(1.0f, layer.alpha); + const renderengine::LayerSettings* layer = layerSettings.back(); + EXPECT_THAT(layer->source.buffer.buffer, IsNull()); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer->source.solidColor); + EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius); + EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace); + EXPECT_EQ(1.0f, layer->alpha); return resultFuture; }); } -- cgit v1.2.3-59-g8ed1b From 59a9f506c7293fdee01482a4bb532df953600d4c Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Tue, 12 Oct 2021 18:53:23 +0000 Subject: Revert^2 "Second Patch for async RenderEngine" Keep the change of Second Patch for async RenderEngine and fix the regression - remove the vector variables which is to store futureFence locally in BufferStateLayer to get avoid fd leaking - screenshots initiated from the app don't wait on the SF main thread. 2109270e74a18585aceffc94d1758cee47bb4175 Bug: 202843200 Bug: 202833127 Bug: 202808760 Test: Wembley PIN setting test, NexusLauncherOutOfProcTests Change-Id: I87847d01e2e330ddec88272cd8608f0b78c0a2cd --- libs/renderengine/RenderEngine.cpp | 2 +- libs/renderengine/gl/GLESRenderEngine.cpp | 66 +++++----- libs/renderengine/gl/GLESRenderEngine.h | 2 +- .../include/renderengine/RenderEngine.h | 4 +- .../include/renderengine/mock/RenderEngine.h | 4 +- libs/renderengine/skia/Cache.cpp | 16 +-- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 113 +++++++++-------- libs/renderengine/skia/SkiaGLRenderEngine.h | 7 +- libs/renderengine/skia/SkiaRenderEngine.h | 2 +- libs/renderengine/tests/RenderEngineTest.cpp | 125 +++++++++---------- .../tests/RenderEngineThreadedTest.cpp | 7 +- .../renderengine/threaded/RenderEngineThreaded.cpp | 11 +- libs/renderengine/threaded/RenderEngineThreaded.h | 4 +- services/surfaceflinger/BufferQueueLayer.cpp | 4 +- services/surfaceflinger/BufferQueueLayer.h | 3 +- services/surfaceflinger/BufferStateLayer.cpp | 88 +++----------- services/surfaceflinger/BufferStateLayer.h | 7 +- .../include/compositionengine/LayerFE.h | 4 +- .../include/compositionengine/mock/LayerFE.h | 2 +- .../CompositionEngine/src/Output.cpp | 23 ++-- .../CompositionEngine/src/planner/CachedSet.cpp | 17 +-- .../CompositionEngine/tests/OutputTest.cpp | 87 +++++++++----- .../tests/planner/CachedSetTest.cpp | 84 ++++++------- services/surfaceflinger/Layer.cpp | 3 +- services/surfaceflinger/Layer.h | 3 +- services/surfaceflinger/RegionSamplingThread.cpp | 11 +- services/surfaceflinger/SurfaceFlinger.cpp | 133 +++++++++++++-------- services/surfaceflinger/SurfaceFlinger.h | 22 ++-- .../surfaceflinger/TransactionCallbackInvoker.cpp | 32 +++++ .../surfaceflinger/TransactionCallbackInvoker.h | 6 +- .../tests/unittests/CompositionTest.cpp | 78 ++++++------ 31 files changed, 513 insertions(+), 457 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index 2174df5515..a9ea690a7c 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -96,7 +96,7 @@ void RenderEngine::validateOutputBufferUsage(const sp& buffer) { } std::future RenderEngine::drawLayers( - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { const auto resultPromise = std::make_shared>(); diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 2375cb7bf1..22dd86698b 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -1080,7 +1080,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer void GLESRenderEngine::drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { ATRACE_CALL(); @@ -1110,10 +1110,10 @@ void GLESRenderEngine::drawLayersInternal( std::unique_ptr fbo; // Gathering layers that requested blur, we'll need them to decide when to render to an // offscreen buffer, and when to render to the native buffer. - std::deque blurLayers; + std::deque blurLayers; if (CC_LIKELY(mBlurFilter != nullptr)) { - for (auto layer : layers) { - if (layer->backgroundBlurRadius > 0) { + for (const auto& layer : layers) { + if (layer.backgroundBlurRadius > 0) { blurLayers.push_back(layer); } } @@ -1137,7 +1137,7 @@ void GLESRenderEngine::drawLayersInternal( } else { setViewportAndProjection(display.physicalDisplay, display.clip); auto status = - mBlurFilter->setAsDrawTarget(display, blurLayers.front()->backgroundBlurRadius); + 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); @@ -1167,7 +1167,7 @@ void GLESRenderEngine::drawLayersInternal( .setTexCoords(2 /* size */) .setCropCoords(2 /* size */) .build(); - for (auto const layer : layers) { + for (const auto& layer : layers) { if (blurLayers.size() > 0 && blurLayers.front() == layer) { blurLayers.pop_front(); @@ -1193,7 +1193,7 @@ void GLESRenderEngine::drawLayersInternal( // There's still something else to blur, so let's keep rendering to our FBO // instead of to the display. status = mBlurFilter->setAsDrawTarget(display, - blurLayers.front()->backgroundBlurRadius); + blurLayers.front().backgroundBlurRadius); } if (status != NO_ERROR) { ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", @@ -1214,42 +1214,42 @@ void GLESRenderEngine::drawLayersInternal( } // Ensure luminance is at least 100 nits to avoid div-by-zero - const float maxLuminance = std::max(100.f, layer->source.buffer.maxLuminanceNits); + const float maxLuminance = std::max(100.f, layer.source.buffer.maxLuminanceNits); mState.maxMasteringLuminance = maxLuminance; mState.maxContentLuminance = maxLuminance; - mState.projectionMatrix = projectionMatrix * layer->geometry.positionTransform; + mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform; - const FloatRect bounds = layer->geometry.boundaries; + const FloatRect bounds = layer.geometry.boundaries; Mesh::VertexArray position(mesh.getPositionArray()); position[0] = vec2(bounds.left, bounds.top); position[1] = vec2(bounds.left, bounds.bottom); position[2] = vec2(bounds.right, bounds.bottom); position[3] = vec2(bounds.right, bounds.top); - setupLayerCropping(*layer, mesh); - setColorTransform(layer->colorTransform); + setupLayerCropping(layer, mesh); + setColorTransform(layer.colorTransform); bool usePremultipliedAlpha = true; bool disableTexture = true; bool isOpaque = false; - if (layer->source.buffer.buffer != nullptr) { + if (layer.source.buffer.buffer != nullptr) { disableTexture = false; - isOpaque = layer->source.buffer.isOpaque; + isOpaque = layer.source.buffer.isOpaque; - sp gBuf = layer->source.buffer.buffer->getBuffer(); + sp gBuf = layer.source.buffer.buffer->getBuffer(); validateInputBufferUsage(gBuf); - bindExternalTextureBuffer(layer->source.buffer.textureName, gBuf, - layer->source.buffer.fence); + bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf, + layer.source.buffer.fence); - usePremultipliedAlpha = layer->source.buffer.usePremultipliedAlpha; - Texture texture(Texture::TEXTURE_EXTERNAL, layer->source.buffer.textureName); - mat4 texMatrix = layer->source.buffer.textureTransform; + usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha; + Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName); + mat4 texMatrix = layer.source.buffer.textureTransform; texture.setMatrix(texMatrix.asArray()); - texture.setFiltering(layer->source.buffer.useTextureFiltering); + texture.setFiltering(layer.source.buffer.useTextureFiltering); texture.setDimensions(gBuf->getWidth(), gBuf->getHeight()); - setSourceY410BT2020(layer->source.buffer.isY410BT2020); + setSourceY410BT2020(layer.source.buffer.isY410BT2020); renderengine::Mesh::VertexArray texCoords(mesh.getTexCoordArray()); texCoords[0] = vec2(0.0, 0.0); @@ -1264,32 +1264,32 @@ void GLESRenderEngine::drawLayersInternal( } } - const half3 solidColor = layer->source.solidColor; - const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer->alpha); + const half3 solidColor = layer.source.solidColor; + const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha); // Buffer sources will have a black solid color ignored in the shader, // so in that scenario the solid color passed here is arbitrary. setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, - layer->geometry.roundedCornersRadius); - if (layer->disableBlending) { + layer.geometry.roundedCornersRadius); + if (layer.disableBlending) { glDisable(GL_BLEND); } - setSourceDataSpace(layer->sourceDataspace); + setSourceDataSpace(layer.sourceDataspace); - if (layer->shadow.length > 0.0f) { - handleShadow(layer->geometry.boundaries, layer->geometry.roundedCornersRadius, - layer->shadow); + if (layer.shadow.length > 0.0f) { + handleShadow(layer.geometry.boundaries, layer.geometry.roundedCornersRadius, + layer.shadow); } // We only want to do a special handling for rounded corners when having rounded corners // is the only reason it needs to turn on blending, otherwise, we handle it like the // usual way since it needs to turn on blending anyway. - else if (layer->geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) { - handleRoundedCorners(display, *layer, mesh); + else if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) { + handleRoundedCorners(display, layer, mesh); } else { drawMesh(mesh); } // Cleanup if there's a buffer source - if (layer->source.buffer.buffer != nullptr) { + if (layer.source.buffer.buffer != nullptr) { disableBlending(); setSourceY410BT2020(false); disableTexturing(); diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index c4adfdf752..1d7c2cafb5 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -104,7 +104,7 @@ protected: bool canSkipPostRenderCleanup() const override; void drawLayersInternal(const std::shared_ptr>&& resultPromise, const DisplaySettings& display, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 701c1f2071..b9cc6485e5 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -160,7 +160,7 @@ public: // @return A future object of RenderEngineResult struct indicating whether // drawing was successful in async mode. virtual std::future drawLayers( - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence); @@ -231,7 +231,7 @@ protected: virtual void drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) = 0; }; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index a7e6809223..248bd652c0 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -49,12 +49,12 @@ public: MOCK_CONST_METHOD0(canSkipPostRenderCleanup, bool()); MOCK_METHOD5(drawLayers, std::future(const DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, base::unique_fd&&)); MOCK_METHOD6(drawLayersInternal, void(const std::shared_ptr>&&, - const DisplaySettings&, const std::vector&, + const DisplaySettings&, const std::vector&, const std::shared_ptr&, const bool, base::unique_fd&&)); MOCK_METHOD0(cleanFramebufferCache, void()); MOCK_METHOD0(getContextPriority, int()); diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index c4fa1bb091..b18a872836 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -95,7 +95,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin .alpha = 1, }; - auto layers = std::vector{&layer, &caster}; + auto layers = std::vector{layer, caster}; // Four combinations of settings are used (two transforms here, and drawShadowLayers is // called with two different destination data spaces) They're all rounded rect. // Three of these are cache misses that generate new shaders. @@ -140,7 +140,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting }}, }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) { layer.sourceDataspace = dataspace; // Cache shaders for both rects and round rects. @@ -176,7 +176,7 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting .alpha = 0.5, }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; for (auto transform : {mat4(), kScaleAndTranslate}) { layer.geometry.positionTransform = transform; for (float roundedCornersRadius : {0.0f, 50.f}) { @@ -201,7 +201,7 @@ static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings .skipContentDraw = true, }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; // Different blur code is invoked for radii less and greater than 30 pixels for (int radius : {9, 60}) { layer.backgroundBlurRadius = radius; @@ -242,7 +242,7 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti }, }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) { layer.source = pixelSource; for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) { @@ -289,7 +289,7 @@ static void drawPIPImageLayer(SkiaRenderEngine* renderengine, const DisplaySetti }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd()); } @@ -317,7 +317,7 @@ static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySett }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd()); } @@ -429,7 +429,7 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { LayerSettings layer{ .source = PixelSource{.solidColor = half3(0.f, 0.f, 0.f)}, }; - auto layers = std::vector{&layer}; + auto layers = std::vector{layer}; // call get() to make it synchronous renderengine ->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd()) diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index cb686a643a..d5ec774e9c 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -610,17 +610,18 @@ private: AutoBackendTexture::CleanupManager& mMgr; }; -sk_sp SkiaGLRenderEngine::createRuntimeEffectShader( - sk_sp shader, - const LayerSettings* layer, const DisplaySettings& display, bool undoPremultipliedAlpha, - bool requiresLinearEffect) { - const auto stretchEffect = layer->stretchEffect; +sk_sp SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp shader, + const LayerSettings& layer, + const DisplaySettings& display, + bool undoPremultipliedAlpha, + bool requiresLinearEffect) { + const auto stretchEffect = layer.stretchEffect; // The given surface will be stretched by HWUI via matrix transformation // which gets similar results for most surfaces // Determine later on if we need to leverage the stertch shader within // surface flinger if (stretchEffect.hasEffect()) { - const auto targetBuffer = layer->source.buffer.buffer; + const auto targetBuffer = layer.source.buffer.buffer; const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr; if (graphicBuffer && shader) { shader = mStretchShaderFactory.createSkShader(shader, stretchEffect); @@ -629,7 +630,7 @@ sk_sp SkiaGLRenderEngine::createRuntimeEffectShader( if (requiresLinearEffect) { const ui::Dataspace inputDataspace = - mUseColorManagement ? layer->sourceDataspace : ui::Dataspace::V0_SRGB_LINEAR; + mUseColorManagement ? layer.sourceDataspace : ui::Dataspace::V0_SRGB_LINEAR; const ui::Dataspace outputDataspace = mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR; @@ -645,13 +646,13 @@ sk_sp SkiaGLRenderEngine::createRuntimeEffectShader( } else { runtimeEffect = effectIter->second; } - float maxLuminance = layer->source.buffer.maxLuminanceNits; + 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, + return createLinearEffectShader(shader, effect, runtimeEffect, layer.colorTransform, display.maxLuminance, maxLuminance); } return shader; @@ -729,7 +730,7 @@ static SkRRect getBlurRRect(const BlurRegion& region) { void SkiaGLRenderEngine::drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool /*useFramebufferCache*/, base::unique_fd&& bufferFence) { ATRACE_NAME("SkiaGL::drawLayers"); @@ -801,11 +802,11 @@ void SkiaGLRenderEngine::drawLayersInternal( if (!layerHasBlur(layer, ctModifiesAlpha)) { continue; } - if (layer->backgroundBlurRadius > 0 && - layer->backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) { + if (layer.backgroundBlurRadius > 0 && + layer.backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) { requiresCompositionLayer = true; } - for (auto region : layer->blurRegions) { + for (auto region : layer.blurRegions) { if (region.blurRadius < BlurFilter::kMaxCrossFadeRadius) { requiresCompositionLayer = true; } @@ -813,7 +814,7 @@ void SkiaGLRenderEngine::drawLayersInternal( if (requiresCompositionLayer) { activeSurface = dstSurface->makeSurface(dstSurface->imageInfo()); canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState); - blurCompositionLayer = layer; + blurCompositionLayer = &layer; break; } } @@ -825,11 +826,11 @@ void SkiaGLRenderEngine::drawLayersInternal( initCanvas(canvas, display); for (const auto& layer : layers) { - ATRACE_FORMAT("DrawLayer: %s", layer->name.c_str()); + ATRACE_FORMAT("DrawLayer: %s", layer.name.c_str()); if (kPrintLayerSettings) { std::stringstream ls; - PrintTo(*layer, &ls); + PrintTo(layer, &ls); auto debugs = ls.str(); int pos = 0; while (pos < debugs.size()) { @@ -839,7 +840,7 @@ void SkiaGLRenderEngine::drawLayersInternal( } sk_sp blurInput; - if (blurCompositionLayer == layer) { + if (blurCompositionLayer == &layer) { LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface); LOG_ALWAYS_FATAL_IF(canvas == dstCanvas); @@ -878,17 +879,17 @@ void SkiaGLRenderEngine::drawLayersInternal( if (CC_UNLIKELY(mCapture->isCaptureRunning())) { // Record the name of the layer if the capture is running. std::stringstream layerSettings; - PrintTo(*layer, &layerSettings); + PrintTo(layer, &layerSettings); // Store the LayerSettings in additional information. - canvas->drawAnnotation(SkRect::MakeEmpty(), layer->name.c_str(), + canvas->drawAnnotation(SkRect::MakeEmpty(), layer.name.c_str(), SkData::MakeWithCString(layerSettings.str().c_str())); } // Layers have a local transform that should be applied to them - canvas->concat(getSkM44(layer->geometry.positionTransform).asM33()); + canvas->concat(getSkM44(layer.geometry.positionTransform).asM33()); const auto [bounds, roundRectClip] = - getBoundsAndClip(layer->geometry.boundaries, layer->geometry.roundedCornersCrop, - layer->geometry.roundedCornersRadius); + getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop, + layer.geometry.roundedCornersRadius); if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) { std::unordered_map> cachedBlurs; @@ -909,20 +910,19 @@ void SkiaGLRenderEngine::drawLayersInternal( // TODO(b/182216890): Filter out empty layers earlier if (blurRect.width() > 0 && blurRect.height() > 0) { - if (layer->backgroundBlurRadius > 0) { + if (layer.backgroundBlurRadius > 0) { ATRACE_NAME("BackgroundBlur"); - auto blurredImage = - mBlurFilter->generate(grContext, layer->backgroundBlurRadius, blurInput, - blurRect); + auto blurredImage = mBlurFilter->generate(grContext, layer.backgroundBlurRadius, + blurInput, blurRect); - cachedBlurs[layer->backgroundBlurRadius] = blurredImage; + cachedBlurs[layer.backgroundBlurRadius] = blurredImage; - mBlurFilter->drawBlurRegion(canvas, bounds, layer->backgroundBlurRadius, 1.0f, + mBlurFilter->drawBlurRegion(canvas, bounds, layer.backgroundBlurRadius, 1.0f, blurRect, blurredImage, blurInput); } - canvas->concat(getSkM44(layer->blurRegionTransform).asM33()); - for (auto region : layer->blurRegions) { + canvas->concat(getSkM44(layer.blurRegionTransform).asM33()); + for (auto region : layer.blurRegions) { if (cachedBlurs[region.blurRadius] == nullptr) { ATRACE_NAME("BlurRegion"); cachedBlurs[region.blurRadius] = @@ -937,19 +937,18 @@ void SkiaGLRenderEngine::drawLayersInternal( } } - if (layer->shadow.length > 0) { + if (layer.shadow.length > 0) { // This would require a new parameter/flag to SkShadowUtils::DrawShadow - LOG_ALWAYS_FATAL_IF(layer->disableBlending, "Cannot disableBlending with a shadow"); + LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow"); SkRRect shadowBounds, shadowClip; - if (layer->geometry.boundaries == layer->shadow.boundaries) { + if (layer.geometry.boundaries == layer.shadow.boundaries) { shadowBounds = bounds; shadowClip = roundRectClip; } else { std::tie(shadowBounds, shadowClip) = - getBoundsAndClip(layer->shadow.boundaries, - layer->geometry.roundedCornersCrop, - layer->geometry.roundedCornersRadius); + getBoundsAndClip(layer.shadow.boundaries, layer.geometry.roundedCornersCrop, + layer.geometry.roundedCornersRadius); } // Technically, if bounds is a rect and roundRectClip is not empty, @@ -960,18 +959,18 @@ void SkiaGLRenderEngine::drawLayersInternal( // looks more like the intent. const auto& rrect = shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds; - drawShadow(canvas, rrect, layer->shadow); + drawShadow(canvas, rrect, layer.shadow); } - const bool requiresLinearEffect = layer->colorTransform != mat4() || + 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->skipContentDraw || - (layer->alpha == 0 && !requiresLinearEffect && !layer->disableBlending && + if (layer.skipContentDraw || + (layer.alpha == 0 && !requiresLinearEffect && !layer.disableBlending && (!displayColorTransform || displayColorTransform->isAlphaUnchanged()))) { continue; } @@ -981,13 +980,13 @@ void SkiaGLRenderEngine::drawLayersInternal( // management is a no-op. const ui::Dataspace layerDataspace = (!mUseColorManagement || requiresLinearEffect) ? dstDataspace - : layer->sourceDataspace; + : layer.sourceDataspace; SkPaint paint; - if (layer->source.buffer.buffer) { + if (layer.source.buffer.buffer) { ATRACE_NAME("DrawImage"); - validateInputBufferUsage(layer->source.buffer.buffer->getBuffer()); - const auto& item = layer->source.buffer; + validateInputBufferUsage(layer.source.buffer.buffer->getBuffer()); + const auto& item = layer.source.buffer; std::shared_ptr imageTextureRef = nullptr; if (const auto& iter = cache.find(item.buffer->getBuffer()->getId()); @@ -1006,8 +1005,8 @@ void SkiaGLRenderEngine::drawLayersInternal( // if the layer's buffer has a fence, then we must must respect the fence prior to using // the buffer. - if (layer->source.buffer.fence != nullptr) { - waitFence(layer->source.buffer.fence->get()); + if (layer.source.buffer.fence != nullptr) { + waitFence(layer.source.buffer.fence->get()); } // isOpaque means we need to ignore the alpha in the image, @@ -1051,7 +1050,7 @@ void SkiaGLRenderEngine::drawLayersInternal( sk_sp shader; - if (layer->source.buffer.useTextureFiltering) { + if (layer.source.buffer.useTextureFiltering) { shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions( {SkFilterMode::kLinear, SkMipmapMode::kNone}), @@ -1069,21 +1068,21 @@ void SkiaGLRenderEngine::drawLayersInternal( paint.setShader(createRuntimeEffectShader(shader, layer, display, !item.isOpaque && item.usePremultipliedAlpha, requiresLinearEffect)); - paint.setAlphaf(layer->alpha); + paint.setAlphaf(layer.alpha); } else { ATRACE_NAME("DrawColor"); - const auto color = layer->source.solidColor; + const auto color = layer.source.solidColor; sk_sp shader = SkShaders::Color(SkColor4f{.fR = color.r, .fG = color.g, .fB = color.b, - .fA = layer->alpha}, + .fA = layer.alpha}, toSkColorSpace(layerDataspace)); paint.setShader(createRuntimeEffectShader(shader, layer, display, /* undoPremultipliedAlpha */ false, requiresLinearEffect)); } - if (layer->disableBlending) { + if (layer.disableBlending) { paint.setBlendMode(SkBlendMode::kSrc); } @@ -1251,13 +1250,13 @@ inline std::pair SkiaGLRenderEngine::getBoundsAndClip(const Fl return {SkRRect::MakeRect(bounds), clip}; } -inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings* layer, +inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings& layer, bool colorTransformModifiesAlpha) { - if (layer->backgroundBlurRadius > 0 || layer->blurRegions.size()) { + if (layer.backgroundBlurRadius > 0 || layer.blurRegions.size()) { // return false if the content is opaque and would therefore occlude the blur - const bool opaqueContent = !layer->source.buffer.buffer || layer->source.buffer.isOpaque; - const bool opaqueAlpha = layer->alpha == 1.0f && !colorTransformModifiesAlpha; - return layer->skipContentDraw || !(opaqueContent && opaqueAlpha); + const bool opaqueContent = !layer.source.buffer.buffer || layer.source.buffer.isOpaque; + const bool opaqueAlpha = layer.alpha == 1.0f && !colorTransformModifiesAlpha; + return layer.skipContentDraw || !(opaqueContent && opaqueAlpha); } return false; } diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index e010c35c13..74ce6513e9 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -74,7 +74,7 @@ protected: bool canSkipPostRenderCleanup() const override; void drawLayersInternal(const std::shared_ptr>&& resultPromise, const DisplaySettings& display, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override; @@ -92,7 +92,7 @@ private: inline SkRect getSkRect(const Rect& layer); inline std::pair getBoundsAndClip(const FloatRect& bounds, const FloatRect& crop, float cornerRadius); - inline bool layerHasBlur(const LayerSettings* layer, bool colorTransformModifiesAlpha); + inline bool layerHasBlur(const LayerSettings& layer, bool colorTransformModifiesAlpha); inline SkColor getSkColor(const vec4& color); inline SkM44 getSkM44(const mat4& matrix); inline SkPoint3 getSkPoint3(const vec3& vector); @@ -108,8 +108,7 @@ private: const ShadowSettings& shadowSettings); // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned. // Otherwise it returns the input shader. - sk_sp createRuntimeEffectShader(sk_sp shader, - const LayerSettings* layer, + sk_sp createRuntimeEffectShader(sk_sp shader, const LayerSettings& layer, const DisplaySettings& display, bool undoPremultipliedAlpha, bool requiresLinearEffect); diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index f61653b940..eb65e83324 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -55,7 +55,7 @@ protected: virtual void drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override { resultPromise->set_value({NO_ERROR, base::unique_fd()}); diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 694bda65d4..c2c05f41b7 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -417,10 +417,11 @@ public: DEFAULT_DISPLAY_HEIGHT - DEFAULT_DISPLAY_OFFSET); } - void invokeDraw(renderengine::DisplaySettings settings, - std::vector layers) { + void invokeDraw(const renderengine::DisplaySettings& settings, + const std::vector& layers) { std::future result = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd()); + ASSERT_TRUE(result.valid()); auto [status, fence] = result.get(); @@ -436,7 +437,7 @@ public: void drawEmptyLayers() { renderengine::DisplaySettings settings; - std::vector layers; + std::vector layers; invokeDraw(settings, layers); } @@ -629,7 +630,7 @@ void RenderEngineTest::fillBuffer(half r, half g, half b, half a) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -637,7 +638,7 @@ void RenderEngineTest::fillBuffer(half r, half g, half b, half a) { SourceVariant::fillColor(layer, r, g, b, this); layer.alpha = a; - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -673,7 +674,7 @@ void RenderEngineTest::fillRedOffsetBuffer() { settings.physicalDisplay = offsetRect(); settings.clip = offsetRectAtZero(); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -681,7 +682,7 @@ void RenderEngineTest::fillRedOffsetBuffer() { SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0f; - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -708,7 +709,7 @@ void RenderEngineTest::fillBufferCheckers(uint32_t orientationFlag) { settings.clip = Rect(2, 2); settings.orientation = orientationFlag; - std::vector layers; + std::vector layers; renderengine::LayerSettings layerOne; layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -731,9 +732,9 @@ void RenderEngineTest::fillBufferCheckers(uint32_t orientationFlag) { SourceVariant::fillColor(layerThree, 0.0f, 0.0f, 1.0f, this); layerThree.alpha = 1.0f; - layers.push_back(&layerOne); - layers.push_back(&layerTwo); - layers.push_back(&layerThree); + layers.push_back(layerOne); + layers.push_back(layerTwo); + layers.push_back(layerThree); invokeDraw(settings, layers); } @@ -810,7 +811,7 @@ void RenderEngineTest::fillBufferWithLayerTransform() { settings.clip = Rect(2, 2); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -821,7 +822,7 @@ void RenderEngineTest::fillBufferWithLayerTransform() { layer.source.solidColor = half3(1.0f, 0.0f, 0.0f); layer.alpha = 1.0f; - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -843,7 +844,7 @@ void RenderEngineTest::fillBufferWithColorTransform() { settings.clip = Rect(1, 1); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -860,7 +861,7 @@ void RenderEngineTest::fillBufferWithColorTransform() { layer.alpha = 1.0f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -877,7 +878,7 @@ void RenderEngineTest::fillBufferWithColorTransformZeroLayerAlpha() { settings.physicalDisplay = fullscreenRect(); settings.clip = Rect(1, 1); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); @@ -890,7 +891,7 @@ void RenderEngineTest::fillBufferWithColorTransformZeroLayerAlpha() { layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -908,7 +909,7 @@ void RenderEngineTest::fillRedBufferWithRoundedCorners() { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -918,7 +919,7 @@ void RenderEngineTest::fillRedBufferWithRoundedCorners() { SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0f; - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -949,14 +950,14 @@ void RenderEngineTest::fillBufferAndBlurBackground() { settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; renderengine::LayerSettings backgroundLayer; backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect(); SourceVariant::fillColor(backgroundLayer, 0.0f, 1.0f, 0.0f, this); backgroundLayer.alpha = 1.0f; - layers.push_back(&backgroundLayer); + layers.emplace_back(backgroundLayer); renderengine::LayerSettings leftLayer; leftLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -964,7 +965,7 @@ void RenderEngineTest::fillBufferAndBlurBackground() { Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT).toFloatRect(); SourceVariant::fillColor(leftLayer, 1.0f, 0.0f, 0.0f, this); leftLayer.alpha = 1.0f; - layers.push_back(&leftLayer); + layers.emplace_back(leftLayer); renderengine::LayerSettings blurLayer; blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -972,7 +973,7 @@ void RenderEngineTest::fillBufferAndBlurBackground() { blurLayer.backgroundBlurRadius = blurRadius; SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this); blurLayer.alpha = 0; - layers.push_back(&blurLayer); + layers.emplace_back(blurLayer); invokeDraw(settings, layers); @@ -994,14 +995,14 @@ void RenderEngineTest::fillSmallLayerAndBlurBackground() { settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; renderengine::LayerSettings backgroundLayer; backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect(); SourceVariant::fillColor(backgroundLayer, 1.0f, 0.0f, 0.0f, this); backgroundLayer.alpha = 1.0f; - layers.push_back(&backgroundLayer); + layers.push_back(backgroundLayer); renderengine::LayerSettings blurLayer; blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1009,7 +1010,7 @@ void RenderEngineTest::fillSmallLayerAndBlurBackground() { blurLayer.backgroundBlurRadius = blurRadius; SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this); blurLayer.alpha = 0; - layers.push_back(&blurLayer); + layers.push_back(blurLayer); invokeDraw(settings, layers); @@ -1026,7 +1027,7 @@ void RenderEngineTest::overlayCorners() { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layersFirst; + std::vector layersFirst; renderengine::LayerSettings layerOne; layerOne.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1035,14 +1036,14 @@ void RenderEngineTest::overlayCorners() { SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this); layerOne.alpha = 0.2; - layersFirst.push_back(&layerOne); + layersFirst.push_back(layerOne); invokeDraw(settings, layersFirst); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 0); - std::vector layersSecond; + std::vector layersSecond; renderengine::LayerSettings layerTwo; layerTwo.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; layerTwo.geometry.boundaries = @@ -1051,7 +1052,7 @@ void RenderEngineTest::overlayCorners() { SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this); layerTwo.alpha = 1.0f; - layersSecond.push_back(&layerTwo); + layersSecond.push_back(layerTwo); invokeDraw(settings, layersSecond); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0); @@ -1066,7 +1067,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() { settings.clip = Rect(1, 1); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1102,7 +1103,7 @@ void RenderEngineTest::fillRedBufferTextureTransform() { layer.alpha = 1.0f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -1118,7 +1119,7 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() { // Here logical space is 1x1 settings.clip = Rect(1, 1); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; const auto buf = allocateSourceBuffer(1, 1); @@ -1141,7 +1142,7 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() { layer.alpha = 0.5f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -1157,7 +1158,7 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() { // Here logical space is 1x1 settings.clip = Rect(1, 1); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; const auto buf = allocateSourceBuffer(1, 1); @@ -1180,7 +1181,7 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() { layer.alpha = 0.5f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -1199,7 +1200,7 @@ void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLaye settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; // add background layer renderengine::LayerSettings bgLayer; @@ -1208,7 +1209,7 @@ void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLaye ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f, backgroundColor.b / 255.0f, this); bgLayer.alpha = backgroundColor.a / 255.0f; - layers.push_back(&bgLayer); + layers.push_back(bgLayer); // add shadow layer renderengine::LayerSettings shadowLayer; @@ -1216,14 +1217,14 @@ void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLaye shadowLayer.geometry.boundaries = castingLayer.geometry.boundaries; shadowLayer.alpha = castingLayer.alpha; shadowLayer.shadow = shadow; - layers.push_back(&shadowLayer); + layers.push_back(shadowLayer); // add layer casting the shadow renderengine::LayerSettings layer = castingLayer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; SourceVariant::fillColor(layer, casterColor.r / 255.0f, casterColor.g / 255.0f, casterColor.b / 255.0f, this); - layers.push_back(&layer); + layers.push_back(layer); invokeDraw(settings, layers); } @@ -1236,7 +1237,7 @@ void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds, settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; // add background layer renderengine::LayerSettings bgLayer; @@ -1245,7 +1246,7 @@ void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds, ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f, backgroundColor.b / 255.0f, this); bgLayer.alpha = backgroundColor.a / 255.0f; - layers.push_back(&bgLayer); + layers.push_back(bgLayer); // add shadow layer renderengine::LayerSettings shadowLayer; @@ -1255,7 +1256,7 @@ void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds, shadowLayer.alpha = 1.0f; ColorSourceVariant::fillColor(shadowLayer, 0, 0, 0, this); shadowLayer.shadow = shadow; - layers.push_back(&shadowLayer); + layers.push_back(shadowLayer); invokeDraw(settings, layers); } @@ -1291,8 +1292,8 @@ TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) { // Transform the red color. bgLayer.colorTransform = mat4(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - std::vector layers; - layers.push_back(&bgLayer); + std::vector layers; + layers.push_back(bgLayer); invokeDraw(settings, layers); @@ -1306,11 +1307,11 @@ TEST_P(RenderEngineTest, drawLayers_nullOutputBuffer) { renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + 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); + layers.push_back(layer); std::future result = mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd()); @@ -1335,12 +1336,12 @@ TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) { settings.physicalDisplay = fullscreenRect(); settings.clip = fullscreenRect(); - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = fullscreenRect().toFloatRect(); BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0; - layers.push_back(&layer); + layers.push_back(layer); std::future result = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd()); @@ -1743,12 +1744,12 @@ TEST_P(RenderEngineTest, cleanupPostRender_cleansUpOnce) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings layer; layer.geometry.boundaries = fullscreenRect().toFloatRect(); BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0; - layers.push_back(&layer); + layers.push_back(layer); std::future resultOne = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd()); @@ -1779,7 +1780,7 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1790,7 +1791,7 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); redLayer.alpha = 1.0f; - layers.push_back(&redLayer); + layers.push_back(redLayer); // Green layer with 1/3 size. renderengine::LayerSettings greenLayer; @@ -1805,7 +1806,7 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f); greenLayer.alpha = 1.0f; - layers.push_back(&greenLayer); + layers.push_back(greenLayer); invokeDraw(settings, layers); @@ -1828,7 +1829,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1839,7 +1840,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); redLayer.alpha = 1.0f; - layers.push_back(&redLayer); + layers.push_back(redLayer); // Green layer with 1/2 size with parent crop rect. renderengine::LayerSettings greenLayer = redLayer; @@ -1847,7 +1848,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT / 2); greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f); - layers.push_back(&greenLayer); + layers.push_back(greenLayer); invokeDraw(settings, layers); @@ -1873,7 +1874,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) { settings.clip = fullscreenRect(); settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; - std::vector layers; + std::vector layers; renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -1884,7 +1885,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) { redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); redLayer.alpha = 1.0f; - layers.push_back(&redLayer); + layers.push_back(redLayer); invokeDraw(settings, layers); // Due to roundedCornersRadius, the top corners are untouched. @@ -1923,7 +1924,7 @@ TEST_P(RenderEngineTest, testClear) { .disableBlending = true, }; - std::vector layers{&redLayer, &clearLayer}; + std::vector layers{redLayer, clearLayer}; invokeDraw(display, layers); expectBufferColor(rect, 0, 0, 0, 0); } @@ -1971,7 +1972,7 @@ TEST_P(RenderEngineTest, testDisableBlendingBuffer) { .disableBlending = true, }; - std::vector layers{&redLayer, &greenLayer}; + std::vector layers{redLayer, greenLayer}; invokeDraw(display, layers); expectBufferColor(rect, 0, 128, 0, 128); } @@ -2017,7 +2018,7 @@ TEST_P(RenderEngineTest, test_isOpaque) { .alpha = 1.0f, }; - std::vector layers{&greenLayer}; + std::vector layers{greenLayer}; invokeDraw(display, layers); if (GetParam()->useColorManagement()) { diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index 99250c1412..db7e12b71b 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -172,20 +172,21 @@ TEST_F(RenderEngineThreadedTest, supportsBackgroundBlur_returnsTrue) { TEST_F(RenderEngineThreadedTest, drawLayers) { renderengine::DisplaySettings settings; - std::vector layers; + std::vector layers; std::shared_ptr buffer = std::make_shared< renderengine::ExternalTexture>(new GraphicBuffer(), *mRenderEngine, renderengine::ExternalTexture::Usage::READABLE | renderengine::ExternalTexture::Usage::WRITEABLE); + base::unique_fd bufferFence; EXPECT_CALL(*mRenderEngine, drawLayersInternal) .WillOnce([&](const std::shared_ptr>&& resultPromise, const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd &&) -> void { + base::unique_fd&&) -> void { resultPromise->set_value({NO_ERROR, base::unique_fd()}); }); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index a549672259..3d446e8e72 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -306,7 +306,7 @@ bool RenderEngineThreaded::canSkipPostRenderCleanup() const { void RenderEngineThreaded::drawLayersInternal( const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { resultPromise->set_value({NO_ERROR, base::unique_fd()}); @@ -314,19 +314,20 @@ void RenderEngineThreaded::drawLayersInternal( } std::future RenderEngineThreaded::drawLayers( - const DisplaySettings& display, const std::vector& layers, + const DisplaySettings& display, const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) { ATRACE_CALL(); const auto resultPromise = std::make_shared>(); std::future resultFuture = resultPromise->get_future(); + int fd = bufferFence.release(); { std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([resultPromise, &display, &layers, &buffer, useFramebufferCache, - &bufferFence](renderengine::RenderEngine& instance) { + mFunctionCalls.push([resultPromise, display, layers, buffer, useFramebufferCache, + fd](renderengine::RenderEngine& instance) { ATRACE_NAME("REThreaded::drawLayers"); instance.drawLayersInternal(std::move(resultPromise), display, layers, buffer, - useFramebufferCache, std::move(bufferFence)); + useFramebufferCache, base::unique_fd(fd)); }); } mCondition.notify_one(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 2303caa7eb..0159cfaece 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -57,7 +57,7 @@ public: void cleanupPostRender() override; std::future drawLayers(const DisplaySettings& display, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override; @@ -73,7 +73,7 @@ protected: bool canSkipPostRenderCleanup() const override; void drawLayersInternal(const std::shared_ptr>&& resultPromise, const DisplaySettings& display, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr& buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence) override; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 52bd420d91..4e5d2d03b0 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -48,7 +48,9 @@ BufferQueueLayer::~BufferQueueLayer() { // Interface implementation for Layer // ----------------------------------------------------------------------- -void BufferQueueLayer::onLayerDisplayed(const sp& releaseFence) { +void BufferQueueLayer::onLayerDisplayed( + std::shared_future futureRenderEngineResult) { + sp releaseFence = new Fence(dup(futureRenderEngineResult.get().drawFence)); mConsumer->setReleaseFence(releaseFence); // Prevent tracing the same release multiple times. diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index a3bd725cfe..dfdb5c055d 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -42,7 +42,8 @@ public: // Implements Layer. const char* getType() const override { return "BufferQueueLayer"; } - void onLayerDisplayed(const sp& releaseFence) override; + void onLayerDisplayed( + std::shared_future futureRenderEngineResult) override; // If a buffer was replaced this frame, release the former buffer void releasePendingBuffer(nsecs_t dequeueReadyTime) override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index fda7a928a1..c213570c7f 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -70,69 +70,11 @@ BufferStateLayer::~BufferStateLayer() { } } -status_t BufferStateLayer::addReleaseFence(const sp& ch, - const sp& fence) { - if (ch == nullptr) { - return OK; - } - ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; - if (!ch->previousReleaseFence.get()) { - ch->previousReleaseFence = fence; - return OK; - } - - // Below logic is lifted from ConsumerBase.cpp: - // Check status of fences first because merging is expensive. - // Merging an invalid fence with any other fence results in an - // invalid fence. - auto currentStatus = ch->previousReleaseFence->getStatus(); - if (currentStatus == Fence::Status::Invalid) { - ALOGE("Existing fence has invalid state, layer: %s", mName.c_str()); - return BAD_VALUE; - } - - auto incomingStatus = fence->getStatus(); - if (incomingStatus == Fence::Status::Invalid) { - ALOGE("New fence has invalid state, layer: %s", mName.c_str()); - ch->previousReleaseFence = fence; - return BAD_VALUE; - } - - // If both fences are signaled or both are unsignaled, we need to merge - // them to get an accurate timestamp. - if (currentStatus == incomingStatus) { - char fenceName[32] = {}; - snprintf(fenceName, 32, "%.28s", mName.c_str()); - sp mergedFence = Fence::merge( - fenceName, ch->previousReleaseFence, fence); - if (!mergedFence.get()) { - ALOGE("failed to merge release fences, layer: %s", mName.c_str()); - // synchronization is broken, the best we can do is hope fences - // signal in order so the new fence will act like a union - ch->previousReleaseFence = fence; - return BAD_VALUE; - } - ch->previousReleaseFence = mergedFence; - } else if (incomingStatus == Fence::Status::Unsignaled) { - // If one fence has signaled and the other hasn't, the unsignaled - // fence will approximately correspond with the correct timestamp. - // There's a small race if both fences signal at about the same time - // and their statuses are retrieved with unfortunate timing. However, - // by this point, they will have both signaled and only the timestamp - // will be slightly off; any dependencies after this point will - // already have been met. - ch->previousReleaseFence = fence; - } - // else if (currentStatus == Fence::Status::Unsignaled) is a no-op. - - return OK; -} - // ----------------------------------------------------------------------- // Interface implementation for Layer // ----------------------------------------------------------------------- -void BufferStateLayer::onLayerDisplayed(const sp& releaseFence) { - +void BufferStateLayer::onLayerDisplayed( + std::shared_future futureRenderEngineResult) { // If a layer has been displayed again we may need to clear // the mLastClientComposition fence that we use for early release in setBuffer // (as we now have a new fence which won't pass through the client composition path in some cases @@ -146,9 +88,6 @@ void BufferStateLayer::onLayerDisplayed(const sp& releaseFence) { mLastClientCompositionDisplayed = true; } - if (!releaseFence->isValid()) { - return; - } // The previous release fence notifies the client that SurfaceFlinger is done with the previous // buffer that was presented on this layer. The first transaction that came in this frame that // replaced the previous buffer on this layer needs this release fence, because the fence will @@ -173,17 +112,17 @@ void BufferStateLayer::onLayerDisplayed(const sp& releaseFence) { break; } } - auto status = addReleaseFence(ch, releaseFence); - if (status != OK) { - ALOGE("Failed to add release fence for layer %s", getName().c_str()); - } - - mPreviousReleaseFence = releaseFence; // Prevent tracing the same release multiple times. if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) { mPreviousReleasedFrameNumber = mPreviousFrameNumber; } + + if (ch != nullptr) { + ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; + ch->previousReleaseFences.emplace_back(futureRenderEngineResult); + ch->name = mName; + } } void BufferStateLayer::onSurfaceFrameCreated( @@ -231,9 +170,18 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { mFlinger->getTransactionCallbackInvoker().addCallbackHandles( mDrawingState.callbackHandles, jankData); + sp releaseFence = Fence::NO_FENCE; + for (auto& handle : mDrawingState.callbackHandles) { + if (handle->releasePreviousBuffer && + mDrawingState.releaseBufferEndpoint == handle->listener) { + releaseFence = + handle->previousReleaseFence ? handle->previousReleaseFence : Fence::NO_FENCE; + break; + } + } + mDrawingState.callbackHandles = {}; - const sp& releaseFence(mPreviousReleaseFence); std::shared_ptr releaseFenceTime = std::make_shared(releaseFence); { Mutex::Autolock lock(mFrameEventHistoryMutex); diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 87b68ea71b..eea700cf7b 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -39,7 +39,9 @@ public: // Implements Layer. const char* getType() const override { return "BufferStateLayer"; } - void onLayerDisplayed(const sp& releaseFence) override; + void onLayerDisplayed( + std::shared_future futureRenderEngineResult) override; + void releasePendingBuffer(nsecs_t dequeueReadyTime) override; void finalizeFrameEventHistory(const std::shared_ptr& glDoneFence, @@ -115,8 +117,6 @@ private: bool updateFrameEventHistory(const sp& acquireFence, nsecs_t postedTime, nsecs_t requestedPresentTime); - status_t addReleaseFence(const sp& ch, const sp& releaseFence); - bool latchSidebandStream(bool& recomputeVisibleRegions) override; bool hasFrameUpdate() const override; @@ -139,7 +139,6 @@ private: std::shared_ptr getBufferFromBufferData( const BufferData& bufferData); - sp mPreviousReleaseFence; ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; uint64_t mPreviousReleasedFrameNumber = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index f7b71cf9fe..ac243c0a17 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -26,6 +27,7 @@ #pragma clang diagnostic ignored "-Wextra" #include +#include // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" @@ -151,7 +153,7 @@ public: ClientCompositionTargetSettings&) = 0; // Called after the layer is displayed to update the presentation fence - virtual void onLayerDisplayed(const sp&) = 0; + virtual void onLayerDisplayed(std::shared_future) = 0; // Gets some kind of identifier for the layer for debug purposes. virtual const char* getDebugName() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index d215bda891..16aebef9f3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -39,7 +39,7 @@ public: std::vector( compositionengine::LayerFE::ClientCompositionTargetSettings&)); - MOCK_METHOD1(onLayerDisplayed, void(const sp&)); + MOCK_METHOD1(onLayerDisplayed, void(std::shared_future)); MOCK_CONST_METHOD0(getDebugName, const char*()); MOCK_CONST_METHOD0(getSequence, int32_t()); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index fad1fa74dd..6800004a90 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -1097,12 +1098,12 @@ std::optional Output::composeSurfaces( setExpensiveRenderingExpected(true); } - std::vector clientCompositionLayerPointers; - clientCompositionLayerPointers.reserve(clientCompositionLayers.size()); + std::vector clientRenderEngineLayers; + clientRenderEngineLayers.reserve(clientCompositionLayers.size()); std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(), - std::back_inserter(clientCompositionLayerPointers), - [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings* { - return &settings; + std::back_inserter(clientRenderEngineLayers), + [](LayerFE::LayerSettings& settings) -> renderengine::LayerSettings { + return settings; }); const nsecs_t renderEngineStart = systemTime(); @@ -1115,7 +1116,7 @@ std::optional Output::composeSurfaces( const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay; auto [status, drawFence] = renderEngine - .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex, + .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, tex, useFramebufferCache, std::move(fd)) .get(); @@ -1295,8 +1296,10 @@ void Output::postFramebuffer() { releaseFence = Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence); } - - layer->getLayerFE().onLayerDisplayed(releaseFence); + layer->getLayerFE().onLayerDisplayed( + ftl::yield( + {NO_ERROR, base::unique_fd(releaseFence->dup())}) + .share()); } // We've got a list of layers needing fences, that are disjoint with @@ -1304,7 +1307,9 @@ void Output::postFramebuffer() { // supply them with the present fence. for (auto& weakLayer : mReleasedLayers) { if (auto layer = weakLayer.promote(); layer != nullptr) { - layer->onLayerDisplayed(frame.presentFence); + layer->onLayerDisplayed(ftl::yield( + {NO_ERROR, base::unique_fd(frame.presentFence->dup())}) + .share()); } } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index e6b716e8f2..ec52e59ab0 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -193,11 +193,6 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te clientCompositionList.cend()); } - std::vector layerSettingsPointers; - std::transform(layerSettings.cbegin(), layerSettings.cend(), - std::back_inserter(layerSettingsPointers), - [](const renderengine::LayerSettings& settings) { return &settings; }); - renderengine::LayerSettings blurLayerSettings; if (mBlurLayer) { auto blurSettings = targetSettings; @@ -212,7 +207,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te blurLayerSettings.name = std::string("blur layer"); // Clear out the shadow settings blurLayerSettings.shadow = {}; - layerSettingsPointers.push_back(&blurLayerSettings); + layerSettings.push_back(blurLayerSettings); } renderengine::LayerSettings holePunchSettings; @@ -230,7 +225,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te holePunchSettings.disableBlending = true; holePunchSettings.alpha = 0.0f; holePunchSettings.name = std::string("hole punch layer"); - layerSettingsPointers.push_back(&holePunchSettings); + layerSettings.push_back(holePunchSettings); // Add a solid background as the first layer in case there is no opaque // buffer behind the punch hole @@ -239,7 +234,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te holePunchBackgroundSettings.geometry.boundaries = holePunchSettings.geometry.boundaries; holePunchBackgroundSettings.geometry.positionTransform = holePunchSettings.geometry.positionTransform; - layerSettingsPointers.insert(layerSettingsPointers.begin(), &holePunchBackgroundSettings); + layerSettings.emplace(layerSettings.begin(), holePunchBackgroundSettings); } if (sDebugHighlighLayers) { @@ -257,7 +252,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te .alpha = half(0.05f), }; - layerSettingsPointers.emplace_back(&highlight); + layerSettings.emplace_back(highlight); } auto texture = texturePool.borrowTexture(); @@ -273,8 +268,8 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te } auto [status, drawFence] = renderEngine - .drawLayers(displaySettings, layerSettingsPointers, - texture->get(), false, std::move(bufferFence)) + .drawLayers(displaySettings, layerSettings, texture->get(), + false, std::move(bufferFence)) .get(); if (status == NO_ERROR) { diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 8f0028c399..cf63ef5183 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -2884,12 +2885,24 @@ TEST_F(OutputPostFramebufferTest, releaseFencesAreSentToLayerFE) { // are passed. This happens to work with the current implementation, but // would not survive certain calls like Fence::merge() which would return a // new instance. - EXPECT_CALL(*mLayer1.layerFE, - onLayerDisplayed(Property(&sp::get, Eq(layer1Fence.get())))); - EXPECT_CALL(*mLayer2.layerFE, - onLayerDisplayed(Property(&sp::get, Eq(layer2Fence.get())))); - EXPECT_CALL(*mLayer3.layerFE, - onLayerDisplayed(Property(&sp::get, Eq(layer3Fence.get())))); + base::unique_fd layer1FD(layer1Fence->dup()); + base::unique_fd layer2FD(layer2Fence->dup()); + base::unique_fd layer3FD(layer3Fence->dup()); + EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_)) + .WillOnce([&layer1FD](std::shared_future + futureRenderEngineResult) { + EXPECT_EQ(layer1FD, futureRenderEngineResult.get().drawFence); + }); + EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_)) + .WillOnce([&layer2FD](std::shared_future + futureRenderEngineResult) { + EXPECT_EQ(layer2FD, futureRenderEngineResult.get().drawFence); + }); + EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_)) + .WillOnce([&layer3FD](std::shared_future + futureRenderEngineResult) { + EXPECT_EQ(layer3FD, futureRenderEngineResult.get().drawFence); + }); mOutput.postFramebuffer(); } @@ -2915,9 +2928,9 @@ TEST_F(OutputPostFramebufferTest, releaseFencesIncludeClientTargetAcquireFence) // Fence::merge is called, and since none of the fences are actually valid, // Fence::NO_FENCE is returned and passed to each onLayerDisplayed() call. // This is the best we can do without creating a real kernel fence object. - EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(Fence::NO_FENCE)); - EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(Fence::NO_FENCE)); - EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(Fence::NO_FENCE)); + EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed).WillOnce(Return()); + EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed).WillOnce(Return()); + EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed).WillOnce(Return()); mOutput.postFramebuffer(); } @@ -2949,12 +2962,22 @@ TEST_F(OutputPostFramebufferTest, releasedLayersSentPresentFence) { EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted()); // Each released layer should be given the presentFence. - EXPECT_CALL(*releasedLayer1, - onLayerDisplayed(Property(&sp::get, Eq(presentFence.get())))); - EXPECT_CALL(*releasedLayer2, - onLayerDisplayed(Property(&sp::get, Eq(presentFence.get())))); - EXPECT_CALL(*releasedLayer3, - onLayerDisplayed(Property(&sp::get, Eq(presentFence.get())))); + base::unique_fd layerFD(presentFence.get()->dup()); + EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_)) + .WillOnce([&layerFD](std::shared_future + futureRenderEngineResult) { + EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence); + }); + EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_)) + .WillOnce([&layerFD](std::shared_future + futureRenderEngineResult) { + EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence); + }); + EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_)) + .WillOnce([&layerFD](std::shared_future + futureRenderEngineResult) { + EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence); + }); mOutput.postFramebuffer(); @@ -3131,9 +3154,9 @@ TEST_F(OutputComposeSurfacesTest, handlesZeroCompositionRequests) { EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); EXPECT_CALL(mRenderEngine, drawLayers(_, IsEmpty(), _, false, _)) .WillRepeatedly([&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd &&) + base::unique_fd&&) -> std::future { return futureOf({NO_ERROR, base::unique_fd()}); }); @@ -3161,11 +3184,11 @@ TEST_F(OutputComposeSurfacesTest, buildsAndRendersRequestList) { })); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) .WillRepeatedly([&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd &&) + base::unique_fd&&) -> std::future { return futureOf({NO_ERROR, base::unique_fd()}); }); @@ -3196,11 +3219,11 @@ TEST_F(OutputComposeSurfacesTest, })); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, true, _)) .WillRepeatedly([&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd &&) + base::unique_fd&&) -> std::future { return futureOf({NO_ERROR, base::unique_fd()}); }); @@ -3226,7 +3249,7 @@ TEST_F(OutputComposeSurfacesTest, renderDuplicateClientCompositionRequestsWithou .WillRepeatedly(Return()); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) .Times(2) .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))) @@ -3258,7 +3281,7 @@ TEST_F(OutputComposeSurfacesTest, skipDuplicateClientCompositionRequests) { .WillRepeatedly(Return()); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false)); @@ -3294,11 +3317,11 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) { EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)) .WillOnce(Return(mOutputBuffer)) .WillOnce(Return(otherOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) .WillRepeatedly([&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd &&) + base::unique_fd&&) -> std::future { return futureOf({NO_ERROR, base::unique_fd()}); }); @@ -3330,10 +3353,10 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfRequestChanges) { .WillRepeatedly(Return()); EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, false, _)) .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); - EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, false, _)) + EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r3), _, false, _)) .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); @@ -3487,9 +3510,9 @@ struct OutputComposeSurfacesTest_HandlesProtectedContent : public OutputComposeS EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _)) .WillRepeatedly( [&](const renderengine::DisplaySettings&, - const std::vector&, + const std::vector&, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { return futureOf( {NO_ERROR, base::unique_fd()}); }); diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index ecb05f8e5f..42b3d972a8 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -346,15 +346,15 @@ TEST_F(CachedSetTest, renderUnsecureOutput) { const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()), displaySettings.orientation); - EXPECT_EQ(0.5f, layers[0]->alpha); - EXPECT_EQ(0.75f, layers[1]->alpha); + EXPECT_EQ(0.5f, layers[0].alpha); + EXPECT_EQ(0.75f, layers[1].alpha); EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace); return futureOf({NO_ERROR, base::unique_fd()}); }; @@ -398,15 +398,15 @@ TEST_F(CachedSetTest, renderSecureOutput) { const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()), displaySettings.orientation); - EXPECT_EQ(0.5f, layers[0]->alpha); - EXPECT_EQ(0.75f, layers[1]->alpha); + EXPECT_EQ(0.5f, layers[0].alpha); + EXPECT_EQ(0.75f, layers[1].alpha); EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace); return futureOf({NO_ERROR, base::unique_fd()}); @@ -453,15 +453,15 @@ TEST_F(CachedSetTest, rendersWithOffsetFramebufferContent) { const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay); EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip); EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()), displaySettings.orientation); - EXPECT_EQ(0.5f, layers[0]->alpha); - EXPECT_EQ(0.75f, layers[1]->alpha); + EXPECT_EQ(0.5f, layers[0].alpha); + EXPECT_EQ(0.75f, layers[1].alpha); EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace); return futureOf({NO_ERROR, base::unique_fd()}); @@ -656,26 +656,26 @@ TEST_F(CachedSetTest, addHolePunch) { const auto drawLayers = [&](const renderengine::DisplaySettings&, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { // If the highlight layer is enabled, it will increase the size by 1. // We're interested in the third layer either way. EXPECT_GE(layers.size(), 4u); { - const auto* holePunchSettings = layers[3]; - EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor); - EXPECT_TRUE(holePunchSettings->disableBlending); - EXPECT_EQ(0.0f, holePunchSettings->alpha); + const auto holePunchSettings = layers[3]; + EXPECT_EQ(nullptr, holePunchSettings.source.buffer.buffer); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings.source.solidColor); + EXPECT_TRUE(holePunchSettings.disableBlending); + EXPECT_EQ(0.0f, holePunchSettings.alpha); } { - const auto* holePunchBackgroundSettings = layers[0]; - EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor); - EXPECT_FALSE(holePunchBackgroundSettings->disableBlending); - EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha); + const auto holePunchBackgroundSettings = layers[0]; + EXPECT_EQ(nullptr, holePunchBackgroundSettings.source.buffer.buffer); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings.source.solidColor); + EXPECT_FALSE(holePunchBackgroundSettings.disableBlending); + EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha); } return futureOf({NO_ERROR, base::unique_fd()}); @@ -717,27 +717,27 @@ TEST_F(CachedSetTest, addHolePunch_noBuffer) { const auto drawLayers = [&](const renderengine::DisplaySettings&, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { // If the highlight layer is enabled, it will increase the size by 1. // We're interested in the third layer either way. EXPECT_GE(layers.size(), 4u); { - const auto* holePunchSettings = layers[3]; - EXPECT_EQ(nullptr, holePunchSettings->source.buffer.buffer); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings->source.solidColor); - EXPECT_TRUE(holePunchSettings->disableBlending); - EXPECT_EQ(0.0f, holePunchSettings->alpha); + const auto holePunchSettings = layers[3]; + EXPECT_EQ(nullptr, holePunchSettings.source.buffer.buffer); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchSettings.source.solidColor); + EXPECT_TRUE(holePunchSettings.disableBlending); + EXPECT_EQ(0.0f, holePunchSettings.alpha); } { - const auto* holePunchBackgroundSettings = layers[0]; - EXPECT_EQ(nullptr, holePunchBackgroundSettings->source.buffer.buffer); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings->source.solidColor); - EXPECT_FALSE(holePunchBackgroundSettings->disableBlending); - EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha); + const auto holePunchBackgroundSettings = layers[0]; + EXPECT_EQ(nullptr, holePunchBackgroundSettings.source.buffer.buffer); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), holePunchBackgroundSettings.source.solidColor); + EXPECT_FALSE(holePunchBackgroundSettings.disableBlending); + EXPECT_EQ(1.0f, holePunchBackgroundSettings.alpha); } return futureOf({NO_ERROR, base::unique_fd()}); @@ -867,16 +867,16 @@ TEST_F(CachedSetTest, addBlur) { const auto drawLayers = [&](const renderengine::DisplaySettings&, - const std::vector& layers, + const std::vector& layers, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { // If the highlight layer is enabled, it will increase the size by 1. // We're interested in the third layer either way. EXPECT_GE(layers.size(), 3u); - const auto* blurSettings = layers[2]; - EXPECT_TRUE(blurSettings->skipContentDraw); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings->source.solidColor); - EXPECT_EQ(0.0f, blurSettings->alpha); + const auto blurSettings = layers[2]; + EXPECT_TRUE(blurSettings.skipContentDraw); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings.source.solidColor); + EXPECT_EQ(0.0f, blurSettings.alpha); return futureOf({NO_ERROR, base::unique_fd()}); }; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5707c67a56..d68cf9720f 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -221,7 +221,8 @@ LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp client, * Layer. So, the implementation is done in BufferLayer. When called on a * EffectLayer object, it's essentially a NOP. */ -void Layer::onLayerDisplayed(const sp& /*releaseFence*/) {} +void Layer::onLayerDisplayed( + std::shared_future /*futureRenderEngineResult*/) {} void Layer::removeRelativeZ(const std::vector& layersInTree) { if (mDrawingState.zOrderRelativeOf == nullptr) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 07b2eb5130..4569f9af23 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -616,7 +616,8 @@ public: void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override; std::vector prepareClientCompositionList( compositionengine::LayerFE::ClientCompositionTargetSettings&) override; - void onLayerDisplayed(const sp& releaseFence) override; + void onLayerDisplayed( + std::shared_future futureRenderEngineResult) override; void setWasClientComposed(const sp& fence) override { mLastClientCompositionFence = fence; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 9465b197b2..32585dd9ac 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -356,10 +356,13 @@ void RegionSamplingThread::captureSample() { renderengine::ExternalTexture::Usage::WRITEABLE); } - const sp captureListener = new SyncScreenCaptureListener(); - mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - true /* regionSampling */, false /* grayscale */, captureListener); - ScreenCaptureResults captureResults = captureListener->waitForResults(); + auto captureScreenResultFuture = + mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, + true /* regionSampling */, false /* grayscale */, nullptr); + auto& captureScreenResult = captureScreenResultFuture.get(); + if (captureScreenResult.drawFence.ok()) { + sync_wait(captureScreenResult.drawFence.get(), -1); + } std::vector activeDescriptors; for (const auto& descriptor : descriptors) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e9665bdec8..da5fefda94 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5923,9 +5923,10 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, traverseLayersInLayerStack(layerStack, args.uid, visitor); }; - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, args.allowProtected, args.grayscale, - captureListener); + auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, + reqSize, args.pixelFormat, args.allowProtected, + args.grayscale, captureListener); + return captureResultFuture.get().status; } status_t SurfaceFlinger::captureDisplay(DisplayId displayId, @@ -5960,9 +5961,15 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId, traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor); }; - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, - ui::PixelFormat::RGBA_8888, false /* allowProtected */, - false /* grayscale */, captureListener); + if (captureListener == nullptr) { + ALOGE("capture screen must provide a capture listener callback"); + return BAD_VALUE; + } + auto captureResultFuture = + captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, + ui::PixelFormat::RGBA_8888, false /* allowProtected */, + false /* grayscale */, captureListener); + return captureResultFuture.get().status; } status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, @@ -6089,23 +6096,28 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, }); }; - return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, - args.pixelFormat, args.allowProtected, args.grayscale, - captureListener); + if (captureListener == nullptr) { + ALOGE("capture screen must provide a capture listener callback"); + return BAD_VALUE; + } + + auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, + reqSize, args.pixelFormat, args.allowProtected, + args.grayscale, captureListener); + return captureResultFuture.get().status; } -status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, - TraverseLayersFunction traverseLayers, - ui::Size bufferSize, ui::PixelFormat reqPixelFormat, - bool allowProtected, bool grayscale, - const sp& captureListener) { +std::shared_future SurfaceFlinger::captureScreenCommon( + RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, + ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale, + const sp& captureListener) { ATRACE_CALL(); if (exceedsMaxRenderTargetSize(bufferSize.getWidth(), bufferSize.getHeight())) { ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32 ") that exceeds render target size limit.", bufferSize.getWidth(), bufferSize.getHeight()); - return BAD_VALUE; + return ftl::yield({BAD_VALUE, base::unique_fd()}).share(); } // Loop over all visible layers to see whether there's any protected layer. A protected layer is @@ -6145,44 +6157,65 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, false /* regionSampling */, grayscale, captureListener); } -status_t SurfaceFlinger::captureScreenCommon( +std::shared_future SurfaceFlinger::captureScreenCommon( RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, const std::shared_ptr& buffer, bool regionSampling, bool grayscale, const sp& captureListener) { ATRACE_CALL(); - if (captureListener == nullptr) { - ALOGE("capture screen must provide a capture listener callback"); - return BAD_VALUE; - } - bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission(); - static_cast(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable { + auto scheduleResultFuture = schedule([=, + renderAreaFuture = std::move(renderAreaFuture)]() mutable + -> std::shared_future { ScreenCaptureResults captureResults; std::unique_ptr renderArea = renderAreaFuture.get(); if (!renderArea) { ALOGW("Skipping screen capture because of invalid render area."); captureResults.result = NO_MEMORY; captureListener->onScreenCaptureCompleted(captureResults); - return; + return ftl::yield({NO_ERROR, base::unique_fd()}) + .share(); } - status_t result = NO_ERROR; + std::shared_future renderEngineResultFuture; + renderArea->render([&] { - result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, - canCaptureBlackoutContent, regionSampling, grayscale, - captureResults); + renderEngineResultFuture = + renderScreenImplLocked(*renderArea, traverseLayers, buffer, + canCaptureBlackoutContent, regionSampling, grayscale, + captureResults); }); + // spring up a thread to unblock SF main thread and wait for + // RenderEngineResult to be available + if (captureListener != nullptr) { + std::async([=]() mutable { + ATRACE_NAME("captureListener is nonnull!"); + auto& [status, drawFence] = renderEngineResultFuture.get(); + captureResults.result = status; + captureResults.fence = new Fence(dup(drawFence)); + captureListener->onScreenCaptureCompleted(captureResults); + }); + } + return renderEngineResultFuture; + }); - captureResults.result = result; - captureListener->onScreenCaptureCompleted(captureResults); - })); - - return NO_ERROR; + // flatten scheduleResultFuture object to single shared_future object + if (captureListener == nullptr) { + std::future captureScreenResultFuture = + ftl::chain(std::move(scheduleResultFuture)) + .then([=](std::shared_future futureObject) + -> renderengine::RenderEngineResult { + auto& [status, drawFence] = futureObject.get(); + return {status, base::unique_fd(dup(drawFence))}; + }); + return captureScreenResultFuture.share(); + } else { + return ftl::yield({NO_ERROR, base::unique_fd()}).share(); + } } -status_t SurfaceFlinger::renderScreenImplLocked( +std::shared_future SurfaceFlinger::renderScreenImplLocked( const RenderArea& renderArea, TraverseLayersFunction traverseLayers, const std::shared_ptr& buffer, bool canCaptureBlackoutContent, bool regionSampling, bool grayscale, @@ -6201,7 +6234,8 @@ status_t SurfaceFlinger::renderScreenImplLocked( // the impetus on WindowManager to not persist them. if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) { ALOGW("FB is protected: PERMISSION_DENIED"); - return PERMISSION_DENIED; + return ftl::yield({PERMISSION_DENIED, base::unique_fd()}) + .share(); } captureResults.buffer = buffer->getBuffer(); @@ -6283,11 +6317,12 @@ status_t SurfaceFlinger::renderScreenImplLocked( }); - std::vector clientCompositionLayerPointers( - clientCompositionLayers.size()); + std::vector clientRenderEngineLayers; + clientRenderEngineLayers.reserve(clientCompositionLayers.size()); std::transform(clientCompositionLayers.begin(), clientCompositionLayers.end(), - clientCompositionLayerPointers.begin(), - std::pointer_traits::pointer_to); + std::back_inserter(clientRenderEngineLayers), + [](compositionengine::LayerFE::LayerSettings& settings) + -> renderengine::LayerSettings { return settings; }); // Use an empty fence for the buffer fence, since we just created the buffer so // there is no need for synchronization with the GPU. @@ -6295,24 +6330,22 @@ status_t SurfaceFlinger::renderScreenImplLocked( getRenderEngine().useProtectedContext(useProtected); const constexpr bool kUseFramebufferCache = false; - auto [status, drawFence] = - getRenderEngine() - .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer, - kUseFramebufferCache, std::move(bufferFence)) - .get(); + std::future drawLayersResult = + getRenderEngine().drawLayers(clientCompositionDisplay, clientRenderEngineLayers, buffer, + kUseFramebufferCache, std::move(bufferFence)); - if (drawFence >= 0) { - sp releaseFence = new Fence(dup(drawFence)); - for (auto* layer : renderedLayers) { - layer->onLayerDisplayed(releaseFence); - } + std::shared_future drawLayersResultFuture = + drawLayersResult.share(); // drawLayersResult will be moved to shared one + + for (auto* layer : renderedLayers) { + // make a copy of shared_future object for each layer + layer->onLayerDisplayed(drawLayersResultFuture); } - captureResults.fence = new Fence(drawFence.release()); // Always switch back to unprotected context. getRenderEngine().useProtectedContext(false); - return status; + return drawLayersResultFuture; } void SurfaceFlinger::windowInfosReported() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index cb1611097a..3dda9f0607 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -809,17 +809,17 @@ private: // Boot animation, on/off animations and screen capture void startBootAnim(); - 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&, - bool regionSampling, bool grayscale, - const sp&); - status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction, - const std::shared_ptr&, - bool canCaptureBlackoutContent, bool regionSampling, - bool grayscale, ScreenCaptureResults&); + std::shared_future captureScreenCommon( + RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, ui::PixelFormat, + bool allowProtected, bool grayscale, const sp&); + std::shared_future captureScreenCommon( + RenderAreaFuture, TraverseLayersFunction, + const std::shared_ptr&, bool regionSampling, + bool grayscale, const sp&); + std::shared_future renderScreenImplLocked( + const RenderArea&, TraverseLayersFunction, + const std::shared_ptr&, bool canCaptureBlackoutContent, + bool regionSampling, bool grayscale, ScreenCaptureResults&); // If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a // matching ownerUid diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index c1eb8966d1..8fbf0b4d07 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -154,6 +154,38 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp& // destroyed the client side is dead and there won't be anyone to send the callback to. sp surfaceControl = handle->surfaceControl.promote(); if (surfaceControl) { + sp prevFence = nullptr; + + for (const auto& futureStruct : handle->previousReleaseFences) { + sp currentFence = sp::make(dup(futureStruct.get().drawFence)); + if (prevFence == nullptr && currentFence->getStatus() != Fence::Status::Invalid) { + prevFence = currentFence; + handle->previousReleaseFence = prevFence; + } else if (prevFence != nullptr) { + // If both fences are signaled or both are unsignaled, we need to merge + // them to get an accurate timestamp. + if (prevFence->getStatus() != Fence::Status::Invalid && + prevFence->getStatus() == currentFence->getStatus()) { + char fenceName[32] = {}; + snprintf(fenceName, 32, "%.28s", handle->name.c_str()); + sp mergedFence = Fence::merge(fenceName, prevFence, currentFence); + if (mergedFence->isValid()) { + handle->previousReleaseFence = mergedFence; + prevFence = handle->previousReleaseFence; + } + } else if (currentFence->getStatus() == Fence::Status::Unsignaled) { + // If one fence has signaled and the other hasn't, the unsignaled + // fence will approximately correspond with the correct timestamp. + // There's a small race if both fences signal at about the same time + // and their statuses are retrieved with unfortunate timing. However, + // by this point, they will have both signaled and only the timestamp + // will be slightly off; any dependencies after this point will + // already have been met. + handle->previousReleaseFence = currentFence; + } + } + } + handle->previousReleaseFences = {}; FrameEventHistoryStats eventStats(handle->frameNumber, handle->gpuCompositionDoneFence->getSnapshot().fence, handle->compositorTiming, handle->refreshStartTime, diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index 7e879e119b..100dbfa8aa 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -18,8 +18,9 @@ #include #include -#include +#include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include +#include #include namespace android { @@ -42,7 +44,9 @@ public: wp surfaceControl; bool releasePreviousBuffer = false; + std::string name; sp previousReleaseFence; + std::vector> previousReleaseFences; nsecs_t acquireTime = -1; nsecs_t latchTime = -1; uint32_t transformHint = 0; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index a0812912d4..40ef6e702d 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -245,10 +245,16 @@ void CompositionTest::captureScreenComposition() { "screenshot"), *mRenderEngine, true); - status_t result = - mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer, - forSystem, regionSampling); - EXPECT_EQ(NO_ERROR, result); + auto result = mFlinger.renderScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer, + forSystem, regionSampling); + EXPECT_TRUE(result.valid()); + + auto& [status, drawFence] = result.get(); + + EXPECT_EQ(NO_ERROR, status); + if (drawFence.ok()) { + sync_wait(drawFence.get(), -1); + } LayerCase::cleanup(this); } @@ -344,9 +350,9 @@ struct BaseDisplayVariant { static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings, - const std::vector&, + const std::vector&, const std::shared_ptr&, - const bool, base::unique_fd &&) + const bool, base::unique_fd&&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), @@ -395,9 +401,9 @@ struct BaseDisplayVariant { Return(0))); EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings, - const std::vector&, + const std::vector&, const std::shared_ptr&, - const bool, base::unique_fd &&) + const bool, base::unique_fd&&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), @@ -631,9 +637,9 @@ struct BaseLayerProperties { static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layerSettings, + const std::vector& layerSettings, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -650,16 +656,16 @@ struct BaseLayerProperties { "verification lambda"; return resultFuture; } - const renderengine::LayerSettings* layer = layerSettings.back(); - EXPECT_THAT(layer->source.buffer.buffer, Not(IsNull())); - EXPECT_THAT(layer->source.buffer.fence, Not(IsNull())); - EXPECT_EQ(DEFAULT_TEXTURE_ID, layer->source.buffer.textureName); - EXPECT_EQ(false, layer->source.buffer.isY410BT2020); - EXPECT_EQ(true, layer->source.buffer.usePremultipliedAlpha); - EXPECT_EQ(false, layer->source.buffer.isOpaque); - EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius); - EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace); - EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha); + const renderengine::LayerSettings layer = layerSettings.back(); + EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull())); + EXPECT_THAT(layer.source.buffer.fence, Not(IsNull())); + EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName); + EXPECT_EQ(false, layer.source.buffer.isY410BT2020); + EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha); + EXPECT_EQ(false, layer.source.buffer.isOpaque); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); + EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); + EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha); return resultFuture; }); } @@ -683,9 +689,9 @@ struct BaseLayerProperties { static void setupREColorCompositionCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layerSettings, + const std::vector& layerSettings, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -702,14 +708,14 @@ struct BaseLayerProperties { "setupREColorCompositionCallExpectations verification lambda"; return resultFuture; } - const renderengine::LayerSettings* layer = layerSettings.back(); - EXPECT_THAT(layer->source.buffer.buffer, IsNull()); + const renderengine::LayerSettings layer = layerSettings.back(); + EXPECT_THAT(layer.source.buffer.buffer, IsNull()); EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1], LayerProperties::COLOR[2]), - layer->source.solidColor); - EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius); - EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace); - EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha); + layer.source.solidColor); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); + EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); + EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha); return resultFuture; }); } @@ -763,9 +769,9 @@ struct CommonSecureLayerProperties : public BaseLayerProperties static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mRenderEngine, drawLayers) .WillOnce([&](const renderengine::DisplaySettings& displaySettings, - const std::vector& layerSettings, + const std::vector& layerSettings, const std::shared_ptr&, const bool, - base::unique_fd &&) -> std::future { + base::unique_fd&&) -> std::future { EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance); EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), displaySettings.physicalDisplay); @@ -782,12 +788,12 @@ struct CommonSecureLayerProperties : public BaseLayerProperties "verification lambda"; return resultFuture; } - const renderengine::LayerSettings* layer = layerSettings.back(); - EXPECT_THAT(layer->source.buffer.buffer, IsNull()); - EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer->source.solidColor); - EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius); - EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace); - EXPECT_EQ(1.0f, layer->alpha); + const renderengine::LayerSettings layer = layerSettings.back(); + EXPECT_THAT(layer.source.buffer.buffer, IsNull()); + EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); + EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); + EXPECT_EQ(1.0f, layer.alpha); return resultFuture; }); } -- cgit v1.2.3-59-g8ed1b From 6eab42d7b60dd1fc23af7f38770fb4d7e23cec79 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Mon, 13 Sep 2021 14:34:13 -0700 Subject: SF: Polish Fps class For consistent comparison (which will later be changed to check ULP distance instead of the magnitude-dependent threshold), express the inequality operators in terms of equality, and avoid hashing floats. Add Hz literals and (namespaced) operators. Bug: 129481165 Bug: 185535769 Test: libsurfaceflinger_unittest Test: dumpsys SurfaceFlinger --vsync Change-Id: I79be5d2dd031218c4054774d2645efb337211538 --- services/surfaceflinger/Fps.h | 142 +- services/surfaceflinger/Layer.cpp | 2 +- services/surfaceflinger/Scheduler/LayerInfo.cpp | 37 +- services/surfaceflinger/Scheduler/LayerInfo.h | 32 +- .../Scheduler/RefreshRateConfigs.cpp | 74 +- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 50 +- .../surfaceflinger/Scheduler/RefreshRateStats.h | 67 +- services/surfaceflinger/Scheduler/Scheduler.cpp | 23 +- .../Scheduler/VsyncConfiguration.cpp | 10 +- .../surfaceflinger/Scheduler/VsyncConfiguration.h | 11 +- services/surfaceflinger/SurfaceFlinger.cpp | 17 +- services/surfaceflinger/TimeStats/TimeStats.h | 14 +- services/surfaceflinger/tests/unittests/FpsOps.h | 49 + .../surfaceflinger/tests/unittests/FpsTest.cpp | 90 +- .../tests/unittests/FrameTimelineTest.cpp | 2 +- .../tests/unittests/LayerHistoryTest.cpp | 80 +- .../tests/unittests/LayerInfoTest.cpp | 33 +- .../tests/unittests/RefreshRateConfigsTest.cpp | 1422 ++++++++------------ .../tests/unittests/RefreshRateStatsTest.cpp | 129 +- .../tests/unittests/SchedulerTest.cpp | 16 +- .../tests/unittests/SetFrameRateTest.cpp | 20 +- .../tests/unittests/TimeStatsTest.cpp | 18 +- .../unittests/TransactionSurfaceFrameTest.cpp | 6 +- .../tests/unittests/VsyncConfigurationTest.cpp | 41 +- 24 files changed, 1078 insertions(+), 1307 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/FpsOps.h (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Fps.h b/services/surfaceflinger/Fps.h index e9f06e5519..639b3e5ed8 100644 --- a/services/surfaceflinger/Fps.h +++ b/services/surfaceflinger/Fps.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * 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. @@ -19,94 +19,110 @@ #include #include #include +#include #include #include 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 duration and frequency. +// Frames per second, stored as floating-point frequency. Provides conversion from/to period in +// nanoseconds, and relational operators with precision threshold. +// +// const Fps fps = 60_Hz; +// +// using namespace fps_approx_ops; +// assert(fps == Fps::fromPeriodNsecs(16'666'667)); +// class Fps { public: - static constexpr Fps fromPeriodNsecs(nsecs_t period) { return Fps(1e9f / period, period); } + constexpr Fps() = default; - Fps() = default; - explicit constexpr Fps(float fps) - : fps(fps), period(fps == 0.0f ? 0 : static_cast(1e9f / fps)) {} + static constexpr Fps fromValue(float frequency) { + return frequency > 0.f ? Fps(frequency, static_cast(1e9f / frequency)) : Fps(); + } - constexpr float getValue() const { return fps; } + static constexpr Fps fromPeriodNsecs(nsecs_t period) { + return period > 0 ? Fps(1e9f / period, period) : Fps(); + } - constexpr nsecs_t getPeriodNsecs() const { return period; } + constexpr bool isValid() const { return mFrequency > 0.f; } - bool equalsWithMargin(const Fps& other) const { return std::abs(fps - other.fps) < kMargin; } + constexpr float getValue() const { return mFrequency; } + int getIntValue() const { return static_cast(std::round(mFrequency)); } - // DO NOT use for std::sort. Instead use comparesLess(). - bool lessThanWithMargin(const Fps& other) const { return fps + kMargin < other.fps; } + constexpr nsecs_t getPeriodNsecs() const { return mPeriod; } - bool greaterThanWithMargin(const Fps& other) const { return fps > other.fps + kMargin; } +private: + constexpr Fps(float frequency, nsecs_t period) : mFrequency(frequency), mPeriod(period) {} - bool lessThanOrEqualWithMargin(const Fps& other) const { return !greaterThanWithMargin(other); } + float mFrequency = 0.f; + nsecs_t mPeriod = 0; +}; - bool greaterThanOrEqualWithMargin(const Fps& other) const { return !lessThanWithMargin(other); } +static_assert(std::is_trivially_copyable_v); - bool isValid() const { return fps > 0.0f; } +constexpr Fps operator""_Hz(unsigned long long frequency) { + return Fps::fromValue(static_cast(frequency)); +} - int getIntValue() const { return static_cast(std::round(fps)); } +constexpr Fps operator""_Hz(long double frequency) { + return Fps::fromValue(static_cast(frequency)); +} - // Use this comparator for sorting. Using a comparator with margins can - // cause std::sort to crash. - inline static bool comparesLess(const Fps& left, const Fps& right) { - return left.fps < right.fps; - } +inline bool isStrictlyLess(Fps lhs, Fps rhs) { + return lhs.getValue() < rhs.getValue(); +} - // Compares two FPS with margin. - // Transitivity is not guaranteed, i.e. a==b and b==c doesn't imply a==c. - // DO NOT use with hash maps. Instead use EqualsInBuckets. - struct EqualsWithMargin { - bool operator()(const Fps& left, const Fps& right) const { - return left.equalsWithMargin(right); - } - }; - - // Equals comparator which can be used with hash maps. - // It's guaranteed that if two elements are equal, then their hashes are equal. - struct EqualsInBuckets { - bool operator()(const Fps& left, const Fps& right) const { - return left.getBucket() == right.getBucket(); - } - }; - - inline friend std::string to_string(const Fps& fps) { - return base::StringPrintf("%.2ffps", fps.fps); - } +// Does not satisfy equivalence relation. +inline bool isApproxEqual(Fps lhs, Fps rhs) { + // TODO(b/185536303): Replace with ULP distance. + return std::abs(lhs.getValue() - rhs.getValue()) < 0.001f; +} - inline friend std::ostream& operator<<(std::ostream& os, const Fps& fps) { - return os << to_string(fps); - } +// Does not satisfy strict weak order. +inline bool isApproxLess(Fps lhs, Fps rhs) { + return isStrictlyLess(lhs, rhs) && !isApproxEqual(lhs, rhs); +} -private: - friend std::hash; +namespace fps_approx_ops { - constexpr Fps(float fps, nsecs_t period) : fps(fps), period(period) {} +inline bool operator==(Fps lhs, Fps rhs) { + return isApproxEqual(lhs, rhs); +} - float getBucket() const { return std::round(fps / kMargin); } +inline bool operator<(Fps lhs, Fps rhs) { + return isApproxLess(lhs, rhs); +} - static constexpr float kMargin = 0.001f; - float fps = 0; - nsecs_t period = 0; -}; +inline bool operator!=(Fps lhs, Fps rhs) { + return !isApproxEqual(lhs, rhs); +} -static_assert(std::is_trivially_copyable_v); +inline bool operator>(Fps lhs, Fps rhs) { + return isApproxLess(rhs, lhs); +} -} // namespace android +inline bool operator<=(Fps lhs, Fps rhs) { + return !isApproxLess(rhs, lhs); +} -namespace std { -template <> -struct hash { - std::size_t operator()(const android::Fps& fps) const { - return std::hash()(fps.getBucket()); - } +inline bool operator>=(Fps lhs, Fps rhs) { + return !isApproxLess(lhs, rhs); +} + +} // namespace fps_approx_ops + +struct FpsApproxEqual { + bool operator()(Fps lhs, Fps rhs) const { return isApproxEqual(lhs, rhs); } }; -} // namespace std \ No newline at end of file + +inline std::string to_string(Fps fps) { + return base::StringPrintf("%.2f Hz", fps.getValue()); +} + +inline std::ostream& operator<<(std::ostream& stream, Fps fps) { + return stream << to_string(fps); +} + +} // namespace android diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5707c67a56..5ee69faa0d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1137,7 +1137,7 @@ bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* tran if (!frameRate.rate.isValid() && frameRate.type != FrameRateCompatibility::NoVote && childrenHaveFrameRate) { *transactionNeeded |= - setFrameRateForLayerTree(FrameRate(Fps(0.0f), FrameRateCompatibility::NoVote)); + setFrameRateForLayerTree(FrameRate(Fps(), FrameRateCompatibility::NoVote)); } // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes for diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 8a45b66b60..314526a99d 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -41,7 +41,7 @@ LayerInfo::LayerInfo(const std::string& name, uid_t ownerUid, : mName(name), mOwnerUid(ownerUid), mDefaultVote(defaultVote), - mLayerVote({defaultVote, Fps(0.0f)}), + mLayerVote({defaultVote, Fps()}), mRefreshRateHistory(name) {} void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType, @@ -93,10 +93,11 @@ bool LayerInfo::isFrequent(nsecs_t now) const { return false; } + using fps_approx_ops::operator>=; + // Layer is considered frequent if the average frame rate is higher than the threshold const auto totalTime = mFrameTimes.back().queueTime - it->queueTime; - return Fps::fromPeriodNsecs(totalTime / (numFrames - 1)) - .greaterThanOrEqualWithMargin(kMinFpsForFrequentLayer); + return Fps::fromPeriodNsecs(totalTime / (numFrames - 1)) >= kMinFpsForFrequentLayer; } bool LayerInfo::isAnimating(nsecs_t now) const { @@ -191,17 +192,17 @@ std::optional LayerInfo::calculateRefreshRateIfPossible( return std::nullopt; } - const auto averageFrameTime = calculateAverageFrameTime(); - if (averageFrameTime.has_value()) { + if (const auto averageFrameTime = calculateAverageFrameTime()) { const auto refreshRate = Fps::fromPeriodNsecs(*averageFrameTime); const bool refreshRateConsistent = mRefreshRateHistory.add(refreshRate, now); if (refreshRateConsistent) { const auto knownRefreshRate = refreshRateConfigs.findClosestKnownFrameRate(refreshRate); - // To avoid oscillation, use the last calculated refresh rate if it is - // close enough + using fps_approx_ops::operator!=; + + // To avoid oscillation, use the last calculated refresh rate if it is close enough. if (std::abs(mLastRefreshRate.calculated.getValue() - refreshRate.getValue()) > MARGIN && - !mLastRefreshRate.reported.equalsWithMargin(knownRefreshRate)) { + mLastRefreshRate.reported != knownRefreshRate) { mLastRefreshRate.calculated = refreshRate; mLastRefreshRate.reported = knownRefreshRate; } @@ -228,15 +229,15 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateConfigs& ref if (isAnimating(now)) { ALOGV("%s is animating", mName.c_str()); mLastRefreshRate.animatingOrInfrequent = true; - return {LayerHistory::LayerVoteType::Max, Fps(0.0f)}; + return {LayerHistory::LayerVoteType::Max, Fps()}; } if (!isFrequent(now)) { ALOGV("%s is infrequent", mName.c_str()); mLastRefreshRate.animatingOrInfrequent = true; - // Infrequent layers vote for mininal refresh rate for + // Infrequent layers vote for minimal refresh rate for // battery saving purposes and also to prevent b/135718869. - return {LayerHistory::LayerVoteType::Min, Fps(0.0f)}; + return {LayerHistory::LayerVoteType::Min, Fps()}; } // If the layer was previously tagged as animating or infrequent, we clear @@ -253,7 +254,7 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateConfigs& ref } ALOGV("%s Max (can't resolve refresh rate)", mName.c_str()); - return {LayerHistory::LayerVoteType::Max, Fps(0.0f)}; + return {LayerHistory::LayerVoteType::Max, Fps()}; } const char* LayerInfo::getTraceTag(android::scheduler::LayerHistory::LayerVoteType type) const { @@ -300,9 +301,13 @@ bool LayerInfo::RefreshRateHistory::add(Fps refreshRate, nsecs_t now) { bool LayerInfo::RefreshRateHistory::isConsistent() const { if (mRefreshRates.empty()) return true; - const auto max = std::max_element(mRefreshRates.begin(), mRefreshRates.end()); - const auto min = std::min_element(mRefreshRates.begin(), mRefreshRates.end()); - const auto consistent = + const auto [min, max] = + std::minmax_element(mRefreshRates.begin(), mRefreshRates.end(), + [](const auto& lhs, const auto& rhs) { + return isStrictlyLess(lhs.refreshRate, rhs.refreshRate); + }); + + const bool consistent = max->refreshRate.getValue() - min->refreshRate.getValue() < MARGIN_CONSISTENT_FPS; if (CC_UNLIKELY(sTraceEnabled)) { @@ -321,4 +326,4 @@ bool LayerInfo::RefreshRateHistory::isConsistent() const { } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index ce9783c5a9..92abbae532 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -51,7 +51,7 @@ class LayerInfo { // is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in // favor of a low refresh rate. static constexpr size_t kFrequentLayerWindowSize = 3; - static constexpr Fps kMinFpsForFrequentLayer{10.0f}; + static constexpr Fps kMinFpsForFrequentLayer = 10_Hz; static constexpr auto kMaxPeriodForFrequentLayerNs = std::chrono::nanoseconds(kMinFpsForFrequentLayer.getPeriodNsecs()) + 1ms; @@ -62,7 +62,7 @@ public: // Holds information about the layer vote struct LayerVote { LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic; - Fps fps{0.0f}; + Fps fps; Seamlessness seamlessness = Seamlessness::Default; }; @@ -86,19 +86,17 @@ public: using Seamlessness = scheduler::Seamlessness; Fps rate; - FrameRateCompatibility type; - Seamlessness seamlessness; + FrameRateCompatibility type = FrameRateCompatibility::Default; + Seamlessness seamlessness = Seamlessness::Default; + + FrameRate() = default; - FrameRate() - : rate(0), - type(FrameRateCompatibility::Default), - seamlessness(Seamlessness::Default) {} FrameRate(Fps rate, FrameRateCompatibility type, Seamlessness seamlessness = Seamlessness::OnlySeamless) : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {} bool operator==(const FrameRate& other) const { - return rate.equalsWithMargin(other.rate) && type == other.type && + return isApproxEqual(rate, other.rate) && type == other.type && seamlessness == other.seamlessness; } @@ -151,7 +149,7 @@ public: void setDefaultLayerVote(LayerHistory::LayerVoteType type) { mDefaultVote = type; } // Resets the layer vote to its default. - void resetLayerVote() { mLayerVote = {mDefaultVote, Fps(0.0f), Seamlessness::Default}; } + void resetLayerVote() { mLayerVote = {mDefaultVote, Fps(), Seamlessness::Default}; } std::string getName() const { return mName; } @@ -201,9 +199,9 @@ private: // Holds information about the calculated and reported refresh rate struct RefreshRateHeuristicData { // Rate calculated on the layer - Fps calculated{0.0f}; + Fps calculated; // Last reported rate for LayerInfo::getRefreshRate() - Fps reported{0.0f}; + Fps reported; // Whether the last reported rate for LayerInfo::getRefreshRate() // was due to animation or infrequent updates bool animatingOrInfrequent = false; @@ -229,14 +227,8 @@ private: // Holds the refresh rate when it was calculated struct RefreshRateData { - Fps refreshRate{0.0f}; + Fps refreshRate; nsecs_t timestamp = 0; - - bool operator<(const RefreshRateData& other) const { - // We don't need comparison with margins since we are using - // this to find the min and max refresh rates. - return refreshRate.getValue() < other.refreshRate.getValue(); - } }; // Holds tracing strings @@ -268,7 +260,7 @@ private: // Used for sanitizing the heuristic data. If two frames are less than // this period apart from each other they'll be considered as duplicates. - static constexpr nsecs_t kMinPeriodBetweenFrames = Fps(240.f).getPeriodNsecs(); + static constexpr nsecs_t kMinPeriodBetweenFrames = (240_Hz).getPeriodNsecs(); // Used for sanitizing the heuristic data. If two frames are more than // this period apart from each other, the interval between them won't be // taken into account when calculating average frame rate. diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index c9f00a0376..aabd88a435 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -42,19 +42,18 @@ std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, f } std::vector constructKnownFrameRates(const DisplayModes& modes) { - std::vector knownFrameRates = {Fps(24.0f), Fps(30.0f), Fps(45.0f), Fps(60.0f), Fps(72.0f)}; + std::vector knownFrameRates = {24_Hz, 30_Hz, 45_Hz, 60_Hz, 72_Hz}; knownFrameRates.reserve(knownFrameRates.size() + modes.size()); - // Add all supported refresh rates to the set + // Add all supported refresh rates. for (const auto& mode : modes) { - const auto refreshRate = Fps::fromPeriodNsecs(mode->getVsyncPeriod()); - knownFrameRates.emplace_back(refreshRate); + knownFrameRates.push_back(Fps::fromPeriodNsecs(mode->getVsyncPeriod())); } - // Sort and remove duplicates - std::sort(knownFrameRates.begin(), knownFrameRates.end(), Fps::comparesLess); + // Sort and remove duplicates. + std::sort(knownFrameRates.begin(), knownFrameRates.end(), isStrictlyLess); knownFrameRates.erase(std::unique(knownFrameRates.begin(), knownFrameRates.end(), - Fps::EqualsWithMargin()), + isApproxEqual), knownFrameRates.end()); return knownFrameRates; } @@ -64,6 +63,11 @@ std::vector constructKnownFrameRates(const DisplayModes& modes) { using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType; using RefreshRate = RefreshRateConfigs::RefreshRate; +bool RefreshRate::inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const { + using fps_approx_ops::operator<=; + return minRefreshRate <= getFps() && getFps() <= maxRefreshRate; +} + std::string RefreshRate::toString() const { return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}", getModeId().value(), mode->getHwcId(), getFps().getValue(), @@ -110,14 +114,14 @@ std::pair RefreshRateConfigs::getDisplayFrames(nsecs_t layerPe bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer, const RefreshRate& refreshRate) const { + using namespace fps_approx_ops; + switch (layer.vote) { case LayerVoteType::ExplicitExactOrMultiple: case LayerVoteType::Heuristic: if (mConfig.frameRateMultipleThreshold != 0 && - refreshRate.getFps().greaterThanOrEqualWithMargin( - Fps(mConfig.frameRateMultipleThreshold)) && - layer.desiredRefreshRate.lessThanWithMargin( - Fps(mConfig.frameRateMultipleThreshold / 2))) { + refreshRate.getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold) && + layer.desiredRefreshRate < Fps::fromValue(mConfig.frameRateMultipleThreshold / 2)) { // Don't vote high refresh rates past the threshold for layers with a low desired // refresh rate. For example, desired 24 fps with 120 Hz threshold means no vote for // 120 Hz, but desired 60 fps should have a vote. @@ -247,7 +251,7 @@ struct RefreshRateScore { }; RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector& layers, - const GlobalSignals& globalSignals, + GlobalSignals globalSignals, GlobalSignals* outSignalsConsidered) const { std::lock_guard lock(mLock); @@ -269,7 +273,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRate(const std::vector RefreshRateConfigs::getCachedBestRefreshRate( - const std::vector& layers, const GlobalSignals& globalSignals, + const std::vector& layers, GlobalSignals globalSignals, GlobalSignals* outSignalsConsidered) const { const bool sameAsLastCall = lastBestRefreshRateInvocation && lastBestRefreshRateInvocation->layerRequirements == layers && @@ -286,7 +290,7 @@ std::optional RefreshRateConfigs::getCachedBestRefreshRate( } RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( - const std::vector& layers, const GlobalSignals& globalSignals, + const std::vector& layers, GlobalSignals globalSignals, GlobalSignals* outSignalsConsidered) const { ATRACE_CALL(); ALOGV("getBestRefreshRate %zu layers", layers.size()); @@ -370,7 +374,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( // move out the of range if layers explicitly request a different refresh // rate. const bool primaryRangeIsSingleRate = - policy->primaryRange.min.equalsWithMargin(policy->primaryRange.max); + isApproxEqual(policy->primaryRange.min, policy->primaryRange.max); if (!globalSignals.touch && globalSignals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { @@ -498,8 +502,11 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( return explicitExact == 0; } }(); + + using fps_approx_ops::operator<; + if (globalSignals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && - bestRefreshRate->getFps().lessThanWithMargin(touchRefreshRate.getFps())) { + bestRefreshRate->getFps() < touchRefreshRate.getFps()) { setTouchConsidered(); ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str()); return touchRefreshRate; @@ -552,7 +559,8 @@ std::vector initializeScoresForAllRefreshRates( } RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverrides( - const std::vector& layers, Fps displayFrameRate, bool touch) const { + const std::vector& layers, Fps displayFrameRate, + GlobalSignals globalSignals) const { ATRACE_CALL(); if (!mSupportsFrameRateOverride) return {}; @@ -570,7 +578,7 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr return layer->vote == LayerVoteType::ExplicitExactOrMultiple; }); - if (touch && hasExplicitExactOrMultiple) { + if (globalSignals.touch && hasExplicitExactOrMultiple) { continue; } @@ -798,8 +806,10 @@ bool RefreshRateConfigs::isPolicyValidLocked(const Policy& policy) const { ALOGE("Default mode is not in the primary range."); return false; } - return policy.appRequestRange.min.lessThanOrEqualWithMargin(policy.primaryRange.min) && - policy.appRequestRange.max.greaterThanOrEqualWithMargin(policy.primaryRange.max); + + using namespace fps_approx_ops; + return policy.appRequestRange.min <= policy.primaryRange.min && + policy.appRequestRange.max >= policy.primaryRange.max; } status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) { @@ -925,19 +935,21 @@ void RefreshRateConfigs::constructAvailableRefreshRates() { } Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const { - if (frameRate.lessThanOrEqualWithMargin(*mKnownFrameRates.begin())) { - return *mKnownFrameRates.begin(); + using namespace fps_approx_ops; + + if (frameRate <= mKnownFrameRates.front()) { + return mKnownFrameRates.front(); } - if (frameRate.greaterThanOrEqualWithMargin(*std::prev(mKnownFrameRates.end()))) { - return *std::prev(mKnownFrameRates.end()); + if (frameRate >= mKnownFrameRates.back()) { + return mKnownFrameRates.back(); } auto lowerBound = std::lower_bound(mKnownFrameRates.begin(), mKnownFrameRates.end(), frameRate, - Fps::comparesLess); + isStrictlyLess); - const auto distance1 = std::abs((frameRate.getValue() - lowerBound->getValue())); - const auto distance2 = std::abs((frameRate.getValue() - std::prev(lowerBound)->getValue())); + const auto distance1 = std::abs(frameRate.getValue() - lowerBound->getValue()); + const auto distance2 = std::abs(frameRate.getValue() - std::prev(lowerBound)->getValue()); return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound); } @@ -956,7 +968,7 @@ RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction } if (minByPolicy == maxByPolicy) { // when min primary range in display manager policy is below device min turn on the timer. - if (currentPolicy->primaryRange.min.lessThanWithMargin(deviceMin.getFps())) { + if (isApproxLess(currentPolicy->primaryRange.min, deviceMin.getFps())) { return RefreshRateConfigs::KernelIdleTimerAction::TurnOn; } return RefreshRateConfigs::KernelIdleTimerAction::TurnOff; @@ -982,14 +994,14 @@ int RefreshRateConfigs::getFrameRateDivider(Fps displayFrameRate, Fps layerFrame } bool RefreshRateConfigs::isFractionalPairOrMultiple(Fps smaller, Fps bigger) { - if (smaller.getValue() > bigger.getValue()) { + if (isStrictlyLess(bigger, smaller)) { return isFractionalPairOrMultiple(bigger, smaller); } const auto multiplier = std::round(bigger.getValue() / smaller.getValue()); constexpr float kCoef = 1000.f / 1001.f; - return bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier / kCoef)) || - bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier * kCoef)); + return isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier / kCoef)) || + isApproxEqual(bigger, Fps::fromValue(smaller.getValue() * multiplier * kCoef)); } void RefreshRateConfigs::dump(std::string& result) const { diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 3abf83d018..53472efae9 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -76,19 +76,15 @@ public: // Checks whether the fps of this RefreshRate struct is within a given min and max refresh // rate passed in. Margin of error is applied to the boundaries for approximation. - bool inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const { - return minRefreshRate.lessThanOrEqualWithMargin(getFps()) && - getFps().lessThanOrEqualWithMargin(maxRefreshRate); - } + bool inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const; - bool operator!=(const RefreshRate& other) const { return mode != other.mode; } + bool operator==(const RefreshRate& other) const { return mode == other.mode; } + bool operator!=(const RefreshRate& other) const { return !operator==(other); } bool operator<(const RefreshRate& other) const { - return getFps().getValue() < other.getFps().getValue(); + return isStrictlyLess(getFps(), other.getFps()); } - bool operator==(const RefreshRate& other) const { return !(*this != other); } - std::string toString() const; friend std::ostream& operator<<(std::ostream& os, const RefreshRate& refreshRate) { return os << refreshRate.toString(); @@ -105,11 +101,11 @@ public: std::unordered_map>; struct FpsRange { - Fps min{0.0f}; - Fps max{std::numeric_limits::max()}; + Fps min = Fps::fromValue(0.f); + Fps max = Fps::fromValue(std::numeric_limits::max()); bool operator==(const FpsRange& other) const { - return min.equalsWithMargin(other.min) && max.equalsWithMargin(other.max); + return isApproxEqual(min, other.min) && isApproxEqual(max, other.max); } bool operator!=(const FpsRange& other) const { return !(*this == other); } @@ -221,7 +217,7 @@ public: // Layer vote type. LayerVoteType vote = LayerVoteType::NoVote; // Layer's desired refresh rate, if applicable. - Fps desiredRefreshRate{0.0f}; + Fps desiredRefreshRate; // If a seamless mode switch is required. Seamlessness seamlessness = Seamlessness::Default; // Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer @@ -232,7 +228,7 @@ public: bool operator==(const LayerRequirement& other) const { return name == other.name && vote == other.vote && - desiredRefreshRate.equalsWithMargin(other.desiredRefreshRate) && + isApproxEqual(desiredRefreshRate, other.desiredRefreshRate) && seamlessness == other.seamlessness && weight == other.weight && focused == other.focused; } @@ -247,18 +243,14 @@ public: // True if the system hasn't seen any buffers posted to layers recently. bool idle = false; - bool operator==(const GlobalSignals& other) const { + bool operator==(GlobalSignals other) const { return touch == other.touch && idle == other.idle; } }; - // Returns the refresh rate that fits best to the given layers. - // layers - The layer requirements to consider. - // globalSignals - global state of touch and idle - // outSignalsConsidered - An output param that tells the caller whether the refresh rate was - // chosen based on touch boost and/or idle timer. - RefreshRate getBestRefreshRate(const std::vector& layers, - const GlobalSignals& globalSignals, + // Returns the refresh rate that best fits the given layers. outSignalsConsidered returns + // whether the refresh rate was chosen based on touch boost and/or idle timer. + RefreshRate getBestRefreshRate(const std::vector&, GlobalSignals, GlobalSignals* outSignalsConsidered = nullptr) const EXCLUDES(mLock); @@ -349,13 +341,10 @@ public: static bool isFractionalPairOrMultiple(Fps, Fps); using UidToFrameRateOverride = std::map; + // Returns the frame rate override for each uid. - // - // @param layers list of visible layers - // @param displayFrameRate the display frame rate - // @param touch whether touch timer is active (i.e. user touched the screen recently) - UidToFrameRateOverride getFrameRateOverrides(const std::vector& layers, - Fps displayFrameRate, bool touch) const + UidToFrameRateOverride getFrameRateOverrides(const std::vector&, + Fps displayFrameRate, GlobalSignals) const EXCLUDES(mLock); bool supportsKernelIdleTimer() const { return mConfig.supportKernelIdleTimer; } @@ -396,13 +385,12 @@ private: const std::function& shouldAddRefreshRate, std::vector* outRefreshRates) REQUIRES(mLock); - std::optional getCachedBestRefreshRate(const std::vector& layers, - const GlobalSignals& globalSignals, + std::optional getCachedBestRefreshRate(const std::vector&, + GlobalSignals, GlobalSignals* outSignalsConsidered) const REQUIRES(mLock); - RefreshRate getBestRefreshRateLocked(const std::vector& layers, - const GlobalSignals& globalSignals, + RefreshRate getBestRefreshRateLocked(const std::vector&, GlobalSignals, GlobalSignals* outSignalsConsidered) const REQUIRES(mLock); // Returns the refresh rate with the highest score in the collection specified from begin diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h index 208a7678ce..80aa96fd63 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateStats.h +++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h @@ -16,15 +16,17 @@ #pragma once +#include #include +#include +#include +#include + #include "Fps.h" #include "Scheduler/SchedulerUtils.h" #include "TimeStats/TimeStats.h" -#include "android-base/stringprintf.h" -#include "utils/Timers.h" - namespace android::scheduler { /** @@ -40,6 +42,7 @@ class RefreshRateStats { static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR; public: + // TODO(b/185535769): Inject clock to avoid sleeping in tests. RefreshRateStats(TimeStats& timeStats, Fps currentRefreshRate, android::hardware::graphics::composer::hal::PowerMode currentPowerMode) : mTimeStats(timeStats), @@ -58,7 +61,7 @@ public: // Sets config mode. If the mode has changed, it records how much time was spent in the previous // mode. void setRefreshRate(Fps currRefreshRate) { - if (mCurrentRefreshRate.equalsWithMargin(currRefreshRate)) { + if (isApproxEqual(mCurrentRefreshRate, currRefreshRate)) { return; } mTimeStats.incrementRefreshRateSwitches(); @@ -66,25 +69,26 @@ public: mCurrentRefreshRate = currRefreshRate; } - // Returns a map between human readable refresh rate and number of seconds the device spent in - // that mode. - std::unordered_map getTotalTimes() { + // Maps stringified refresh rate to total time spent in that mode. + using TotalTimes = ftl::SmallMap; + + TotalTimes getTotalTimes() { // If the power mode is on, then we are probably switching between the config modes. If // it's not then the screen is probably off. Make sure to flush times before printing // them. flushTime(); - std::unordered_map totalTime; - // Multiple configs may map to the same name, e.g. "60fps". Add the - // times for such configs together. - for (const auto& [configId, time] : mConfigModesTotalTime) { - totalTime[to_string(configId)] = 0; - } - for (const auto& [configId, time] : mConfigModesTotalTime) { - totalTime[to_string(configId)] += time; + TotalTimes totalTimes = ftl::init::map("ScreenOff", mScreenOffTime); + const auto zero = std::chrono::milliseconds::zero(); + + // Sum the times for modes that map to the same name, e.g. "60 Hz". + for (const auto& [fps, time] : mFpsTotalTimes) { + const auto string = to_string(fps); + const auto total = std::as_const(totalTimes).get(string).value_or(std::cref(zero)); + totalTimes.emplace_or_replace(string, total.get() + time); } - totalTime["ScreenOff"] = mScreenOffTime; - return totalTime; + + return totalTimes; } // Traverses through the map of config modes and returns how long they've been running in easy @@ -102,28 +106,32 @@ private: // Calculates the time that passed in ms between the last time we recorded time and the time // this method was called. void flushTime() { - nsecs_t currentTime = systemTime(); - nsecs_t timeElapsed = currentTime - mPreviousRecordedTime; - int64_t timeElapsedMs = ns2ms(timeElapsed); + const nsecs_t currentTime = systemTime(); + const nsecs_t timeElapsed = currentTime - mPreviousRecordedTime; mPreviousRecordedTime = currentTime; + const auto duration = std::chrono::milliseconds{ns2ms(timeElapsed)}; + const auto zero = std::chrono::milliseconds::zero(); + uint32_t fps = 0; + if (mCurrentPowerMode == android::hardware::graphics::composer::hal::PowerMode::ON) { // Normal power mode is counted under different config modes. - if (mConfigModesTotalTime.find(mCurrentRefreshRate) == mConfigModesTotalTime.end()) { - mConfigModesTotalTime[mCurrentRefreshRate] = 0; - } - mConfigModesTotalTime[mCurrentRefreshRate] += timeElapsedMs; + const auto total = std::as_const(mFpsTotalTimes) + .get(mCurrentRefreshRate) + .value_or(std::cref(zero)); + mFpsTotalTimes.emplace_or_replace(mCurrentRefreshRate, total.get() + duration); + fps = static_cast(mCurrentRefreshRate.getIntValue()); } else { - mScreenOffTime += timeElapsedMs; + mScreenOffTime += duration; } mTimeStats.recordRefreshRate(fps, timeElapsed); } // Formats the time in milliseconds into easy to read format. - static std::string getDateFormatFromMs(int64_t timeMs) { - auto [days, dayRemainderMs] = std::div(timeMs, MS_PER_DAY); + static std::string getDateFormatFromMs(std::chrono::milliseconds time) { + auto [days, dayRemainderMs] = std::div(static_cast(time.count()), MS_PER_DAY); auto [hours, hourRemainderMs] = std::div(dayRemainderMs, MS_PER_HOUR); auto [mins, minsRemainderMs] = std::div(hourRemainderMs, MS_PER_MIN); auto [sec, secRemainderMs] = std::div(minsRemainderMs, MS_PER_S); @@ -138,9 +146,8 @@ private: Fps mCurrentRefreshRate; android::hardware::graphics::composer::hal::PowerMode mCurrentPowerMode; - std::unordered_map, Fps::EqualsInBuckets> - mConfigModesTotalTime; - int64_t mScreenOffTime = 0; + ftl::SmallMap mFpsTotalTimes; + std::chrono::milliseconds mScreenOffTime = std::chrono::milliseconds::zero(); nsecs_t mPreviousRecordedTime = systemTime(); }; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index c6a19de9c6..47b3568770 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -206,14 +206,14 @@ std::optional Scheduler::getFrameRateOverride(uid_t uid) const { { const auto iter = mFrameRateOverridesFromBackdoor.find(uid); if (iter != mFrameRateOverridesFromBackdoor.end()) { - return std::make_optional(iter->second); + return iter->second; } } { const auto iter = mFrameRateOverridesByContent.find(uid); if (iter != mFrameRateOverridesByContent.end()) { - return std::make_optional(iter->second); + return iter->second; } } @@ -697,15 +697,16 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { return mRefreshRateConfigs->getCurrentRefreshRate(); }(); - constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER{65.0f}; - if (state == TimerState::Reset && - refreshRate.getFps().greaterThanWithMargin(FPS_THRESHOLD_FOR_KERNEL_TIMER)) { + constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz; + using namespace fps_approx_ops; + + if (state == TimerState::Reset && refreshRate.getFps() > FPS_THRESHOLD_FOR_KERNEL_TIMER) { // If we're not in performance mode then the kernel timer shouldn't do // anything, as the refresh rate during DPU power collapse will be the // same. resyncToHardwareVsync(true /* makeAvailable */, refreshRate.getVsyncPeriod()); } else if (state == TimerState::Expired && - refreshRate.getFps().lessThanOrEqualWithMargin(FPS_THRESHOLD_FOR_KERNEL_TIMER)) { + refreshRate.getFps() <= FPS_THRESHOLD_FOR_KERNEL_TIMER) { // Disable HW VSYNC if the timer expired, as we don't need it enabled if // we're not pushing frames, and if we're in PERFORMANCE mode then we'll // need to update the VsyncController model anyway. @@ -781,13 +782,12 @@ bool Scheduler::updateFrameRateOverrides( if (!consideredSignals.idle) { const auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(mFeatures.contentRequirements, - displayRefreshRate, - consideredSignals.touch); + displayRefreshRate, consideredSignals); std::lock_guard lock(mFrameRateOverridesLock); if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(), frameRateOverrides.begin(), frameRateOverrides.end(), - [](const std::pair& a, const std::pair& b) { - return a.first == b.first && a.second.equalsWithMargin(b.second); + [](const auto& lhs, const auto& rhs) { + return lhs.first == rhs.first && isApproxEqual(lhs.second, rhs.second); })) { mFrameRateOverridesByContent = frameRateOverrides; return true; @@ -912,7 +912,8 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid std::lock_guard lock(mFrameRateOverridesLock); if (frameRateOverride.frameRateHz != 0.f) { - mFrameRateOverridesFromBackdoor[frameRateOverride.uid] = Fps(frameRateOverride.frameRateHz); + mFrameRateOverridesFromBackdoor[frameRateOverride.uid] = + Fps::fromValue(frameRateOverride.frameRateHz); } else { mFrameRateOverridesFromBackdoor.erase(frameRateOverride.uid); } diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp index 43e02979c1..ff316515b6 100644 --- a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp +++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp @@ -48,14 +48,12 @@ PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRate(Fps fp } PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRateLocked(Fps fps) const { - const auto iter = mOffsetsCache.find(fps); - if (iter != mOffsetsCache.end()) { - return iter->second; + if (const auto offsets = mOffsetsCache.get(fps)) { + return offsets->get(); } - const auto offset = constructOffsets(fps.getPeriodNsecs()); - mOffsetsCache[fps] = offset; - return offset; + const auto [it, _] = mOffsetsCache.try_emplace(fps, constructOffsets(fps.getPeriodNsecs())); + return it->second; } void VsyncConfiguration::dump(std::string& result) const { diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.h b/services/surfaceflinger/Scheduler/VsyncConfiguration.h index 3e53b3faa2..844751270e 100644 --- a/services/surfaceflinger/Scheduler/VsyncConfiguration.h +++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.h @@ -17,10 +17,10 @@ #pragma once #include -#include -#include -#include +#include +#include +#include #include #include "Fps.h" @@ -88,9 +88,8 @@ protected: VsyncConfigSet getConfigsForRefreshRateLocked(Fps fps) const REQUIRES(mLock); - mutable std::unordered_map, Fps::EqualsInBuckets> - mOffsetsCache GUARDED_BY(mLock); - std::atomic mRefreshRateFps GUARDED_BY(mLock); + mutable ftl::SmallMap mOffsetsCache GUARDED_BY(mLock); + Fps mRefreshRateFps GUARDED_BY(mLock); mutable std::mutex mLock; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e9665bdec8..be5c2cf39c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1039,7 +1039,7 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp& displayToken, outMode.refreshRate = Fps::fromPeriodNsecs(period).getValue(); const auto vsyncConfigSet = - mVsyncConfiguration->getConfigsForRefreshRate(Fps(outMode.refreshRate)); + mVsyncConfiguration->getConfigsForRefreshRate(Fps::fromValue(outMode.refreshRate)); outMode.appVsyncOffset = vsyncConfigSet.late.appOffset; outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset; outMode.group = mode->getGroup(); @@ -4099,7 +4099,8 @@ uint32_t SurfaceFlinger::setClientStateLocked( const auto strategy = Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy); - if (layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate), compatibility, strategy))) { + if (layer->setFrameRate( + Layer::FrameRate(Fps::fromValue(s.frameRate), compatibility, strategy))) { flags |= eTraversalNeeded; } } @@ -6440,8 +6441,10 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecs( using Policy = scheduler::RefreshRateConfigs::Policy; const Policy policy{DisplayModeId(defaultMode), allowGroupSwitching, - {Fps(primaryRefreshRateMin), Fps(primaryRefreshRateMax)}, - {Fps(appRequestRefreshRateMin), Fps(appRequestRefreshRateMax)}}; + {Fps::fromValue(primaryRefreshRateMin), + Fps::fromValue(primaryRefreshRateMax)}, + {Fps::fromValue(appRequestRefreshRateMin), + Fps::fromValue(appRequestRefreshRateMax)}}; constexpr bool kOverridePolicy = false; return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy); @@ -6573,7 +6576,7 @@ status_t SurfaceFlinger::setFrameRate(const sp& surface, const auto strategy = Layer::FrameRate::convertChangeFrameRateStrategy(changeFrameRateStrategy); if (layer->setFrameRate( - Layer::FrameRate(Fps{frameRate}, + Layer::FrameRate(Fps::fromValue(frameRate), Layer::FrameRate::convertCompatibility(compatibility), strategy))) { setTransactionFlags(eTraversalNeeded); @@ -6707,7 +6710,7 @@ int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate, } status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const { - Fps maxRefreshRate(60.f); + Fps maxRefreshRate = 60_Hz; if (!getHwComposer().isHeadless()) { if (const auto display = getDefaultDisplayDevice()) { @@ -6720,7 +6723,7 @@ status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const { } uint32_t SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const { - Fps refreshRate(60.f); + Fps refreshRate = 60_Hz; if (const auto frameRateOverride = mScheduler->getFrameRateOverride(uid)) { refreshRate = *frameRateOverride; diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 9e70684023..bdeaeb8468 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -129,13 +129,15 @@ public: nsecs_t displayPresentJitter = 0; nsecs_t appDeadlineDelta = 0; + static bool isOptApproxEqual(std::optional lhs, std::optional rhs) { + return (!lhs && !rhs) || (lhs && rhs && isApproxEqual(*lhs, *rhs)); + } + bool operator==(const JankyFramesInfo& o) const { - return Fps::EqualsInBuckets{}(refreshRate, o.refreshRate) && - ((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 && gameMode == o.gameMode && - reasons == o.reasons && displayDeadlineDelta == o.displayDeadlineDelta && + return isApproxEqual(refreshRate, o.refreshRate) && + isOptApproxEqual(renderRate, o.renderRate) && uid == o.uid && + layerName == o.layerName && gameMode == o.gameMode && reasons == o.reasons && + displayDeadlineDelta == o.displayDeadlineDelta && displayPresentJitter == o.displayPresentJitter && appDeadlineDelta == o.appDeadlineDelta; } diff --git a/services/surfaceflinger/tests/unittests/FpsOps.h b/services/surfaceflinger/tests/unittests/FpsOps.h new file mode 100644 index 0000000000..23c2841efc --- /dev/null +++ b/services/surfaceflinger/tests/unittests/FpsOps.h @@ -0,0 +1,49 @@ +/* + * 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 "Fps.h" + +namespace android { + +// Pull Fps operators into its namespace to enable ADL for EXPECT_EQ, EXPECT_LT, etc. + +inline bool operator==(Fps lhs, Fps rhs) { + return fps_approx_ops::operator==(lhs, rhs); +} + +inline bool operator<(Fps lhs, Fps rhs) { + return fps_approx_ops::operator<(lhs, rhs); +} + +inline bool operator!=(Fps lhs, Fps rhs) { + return fps_approx_ops::operator!=(lhs, rhs); +} + +inline bool operator>(Fps lhs, Fps rhs) { + return fps_approx_ops::operator>(lhs, rhs); +} + +inline bool operator<=(Fps lhs, Fps rhs) { + return fps_approx_ops::operator<=(lhs, rhs); +} + +inline bool operator>=(Fps lhs, Fps rhs) { + return fps_approx_ops::operator>=(lhs, rhs); +} + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/FpsTest.cpp b/services/surfaceflinger/tests/unittests/FpsTest.cpp index db732cfeaf..b44dd89229 100644 --- a/services/surfaceflinger/tests/unittests/FpsTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsTest.cpp @@ -15,6 +15,7 @@ */ #include "Fps.h" +#include "FpsOps.h" #include #include @@ -22,77 +23,48 @@ namespace android { TEST(FpsTest, construct) { - Fps fpsDefault; - EXPECT_FALSE(fpsDefault.isValid()); + EXPECT_FALSE(Fps().isValid()); - Fps fps1(60.0f); - EXPECT_TRUE(fps1.isValid()); - Fps fps2 = Fps::fromPeriodNsecs(static_cast(1e9f / 60.0f)); - EXPECT_TRUE(fps2.isValid()); - EXPECT_TRUE(fps1.equalsWithMargin(fps2)); -} - -TEST(FpsTest, compare) { - constexpr float kEpsilon = 1e-4f; - const Fps::EqualsInBuckets equalsInBuckets; - const Fps::EqualsWithMargin equalsWithMargin; + EXPECT_FALSE((0_Hz).isValid()); + EXPECT_TRUE((120_Hz).isValid()); + EXPECT_TRUE((0.5_Hz).isValid()); - EXPECT_TRUE(Fps(60.0f).equalsWithMargin(Fps(60.f))); - EXPECT_TRUE(Fps(60.0f).equalsWithMargin(Fps(60.f - kEpsilon))); - EXPECT_TRUE(Fps(60.0f).equalsWithMargin(Fps(60.f + kEpsilon))); + EXPECT_FALSE(Fps::fromPeriodNsecs(0).isValid()); - EXPECT_TRUE(equalsInBuckets(Fps(60.0f), Fps(60.0f))); - EXPECT_TRUE(equalsInBuckets(Fps(60.0f), Fps(60.0f - kEpsilon))); - EXPECT_TRUE(equalsInBuckets(Fps(60.0f), Fps(60.0f + kEpsilon))); + const Fps fps = Fps::fromPeriodNsecs(16'666'667); + EXPECT_TRUE(fps.isValid()); + EXPECT_EQ(fps, 60_Hz); +} - EXPECT_TRUE(equalsWithMargin(Fps(60.0f), Fps(60.0f))); - EXPECT_TRUE(equalsWithMargin(Fps(60.0f), Fps(60.0f - kEpsilon))); - EXPECT_TRUE(equalsWithMargin(Fps(60.0f), Fps(60.0f + kEpsilon))); +TEST(FpsTest, compare) { + EXPECT_EQ(60_Hz, 60_Hz); + EXPECT_EQ(60_Hz, 59.9999_Hz); + EXPECT_EQ(60_Hz, 60.0001_Hz); - EXPECT_TRUE(Fps(60.0f).lessThanOrEqualWithMargin(Fps(60.f + kEpsilon))); - EXPECT_TRUE(Fps(60.0f).lessThanOrEqualWithMargin(Fps(60.f))); - EXPECT_TRUE(Fps(60.0f).lessThanOrEqualWithMargin(Fps(60.f - kEpsilon))); + EXPECT_LE(60_Hz, 60_Hz); + EXPECT_LE(60_Hz, 59.9999_Hz); + EXPECT_LE(60_Hz, 60.0001_Hz); - EXPECT_TRUE(Fps(60.0f).greaterThanOrEqualWithMargin(Fps(60.f + kEpsilon))); - EXPECT_TRUE(Fps(60.0f).greaterThanOrEqualWithMargin(Fps(60.f))); - EXPECT_TRUE(Fps(60.0f).greaterThanOrEqualWithMargin(Fps(60.f - kEpsilon))); + EXPECT_GE(60_Hz, 60_Hz); + EXPECT_GE(60_Hz, 59.9999_Hz); + EXPECT_GE(60_Hz, 60.0001_Hz); - // Fps with difference of 1 should be different - EXPECT_FALSE(Fps(60.0f).equalsWithMargin(Fps(61.f))); - EXPECT_TRUE(Fps(60.0f).lessThanWithMargin(Fps(61.f))); - EXPECT_TRUE(Fps(60.0f).greaterThanWithMargin(Fps(59.f))); + // Fps with difference of 1 should be different. + EXPECT_NE(60_Hz, 61_Hz); + EXPECT_LT(60_Hz, 61_Hz); + EXPECT_GT(60_Hz, 59_Hz); // These are common refresh rates which should be different. - EXPECT_FALSE(Fps(60.0f).equalsWithMargin(Fps(59.94f))); - EXPECT_TRUE(Fps(60.0f).greaterThanWithMargin(Fps(59.94f))); - EXPECT_FALSE(equalsInBuckets(Fps(60.0f), Fps(59.94f))); - EXPECT_FALSE(equalsWithMargin(Fps(60.0f), Fps(59.94f))); - EXPECT_NE(std::hash()(Fps(60.0f)), std::hash()(Fps(59.94f))); - - EXPECT_FALSE(Fps(30.0f).equalsWithMargin(Fps(29.97f))); - EXPECT_TRUE(Fps(30.0f).greaterThanWithMargin(Fps(29.97f))); - EXPECT_FALSE(equalsInBuckets(Fps(30.0f), Fps(29.97f))); - EXPECT_FALSE(equalsWithMargin(Fps(30.0f), Fps(29.97f))); - EXPECT_NE(std::hash()(Fps(30.0f)), std::hash()(Fps(29.97f))); + EXPECT_NE(60_Hz, 59.94_Hz); + EXPECT_GT(60_Hz, 59.94_Hz); + EXPECT_NE(30_Hz, 29.97_Hz); + EXPECT_GT(30_Hz, 29.97_Hz); } TEST(FpsTest, getIntValue) { - EXPECT_EQ(30, Fps(30.1f).getIntValue()); - EXPECT_EQ(31, Fps(30.9f).getIntValue()); - EXPECT_EQ(31, Fps(30.5f).getIntValue()); -} - -TEST(FpsTest, equalsInBucketsImpliesEqualHashes) { - constexpr float kStep = 1e-4f; - const Fps::EqualsInBuckets equals; - for (float fps = 30.0f; fps < 31.0f; fps += kStep) { - const Fps left(fps); - const Fps right(fps + kStep); - if (equals(left, right)) { - ASSERT_EQ(std::hash()(left), std::hash()(right)) - << "left= " << left << " right=" << right; - } - } + EXPECT_EQ(30, (30.1_Hz).getIntValue()); + EXPECT_EQ(31, (30.9_Hz).getIntValue()); + EXPECT_EQ(31, (30.5_Hz).getIntValue()); } } // namespace android diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index 97b60e0d8b..9fbaeced7b 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -559,7 +559,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { - Fps refreshRate = Fps(11.0); + Fps refreshRate = 11_Hz; EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, sLayerNameOne, sGameMode, diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index bb21ad63db..e8795fea22 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -26,6 +26,7 @@ #include #include +#include "FpsOps.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/LayerInfo.h" #include "TestableScheduler.h" @@ -50,10 +51,10 @@ protected: static constexpr auto REFRESH_RATE_AVERAGE_HISTORY_DURATION = LayerInfo::RefreshRateHistory::HISTORY_DURATION; - static constexpr Fps LO_FPS{30.f}; + static constexpr Fps LO_FPS = 30_Hz; static constexpr auto LO_FPS_PERIOD = LO_FPS.getPeriodNsecs(); - static constexpr Fps HI_FPS{90.f}; + static constexpr Fps HI_FPS = 90_Hz; static constexpr auto HI_FPS_PERIOD = HI_FPS.getPeriodNsecs(); LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); } @@ -111,8 +112,7 @@ protected: ASSERT_EQ(1, summary.size()); ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); - ASSERT_TRUE(desiredRefreshRate.equalsWithMargin(summary[0].desiredRefreshRate)) - << "Frame rate is " << frameRate; + ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate); } std::shared_ptr mConfigs = std::make_shared< @@ -149,7 +149,7 @@ TEST_F(LayerHistoryTest, oneLayer) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); - const nsecs_t time = systemTime(); + nsecs_t time = systemTime(); // No layers returned if no layers are active. EXPECT_TRUE(summarizeLayerHistory(time).empty()); @@ -161,6 +161,7 @@ TEST_F(LayerHistoryTest, oneLayer) { ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); + time += LO_FPS_PERIOD; } // Max is returned since we have enough history but there is no timestamp votes. @@ -169,6 +170,7 @@ TEST_F(LayerHistoryTest, oneLayer) { ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); + time += LO_FPS_PERIOD; } } @@ -213,7 +215,7 @@ TEST_F(LayerHistoryTest, explicitTimestamp) { ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote); - EXPECT_TRUE(LO_FPS.equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate)); + EXPECT_EQ(LO_FPS, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); } @@ -306,7 +308,7 @@ TEST_F(LayerHistoryTest, oneLayerExplicitVote) { EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly( - Return(Layer::FrameRate(Fps(73.4f), Layer::FrameRateCompatibility::Default))); + Return(Layer::FrameRate(73.4_Hz, Layer::FrameRateCompatibility::Default))); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -319,7 +321,7 @@ TEST_F(LayerHistoryTest, oneLayerExplicitVote) { ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote); - EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate)); + EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); @@ -328,7 +330,7 @@ TEST_F(LayerHistoryTest, oneLayerExplicitVote) { time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote); - EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate)); + EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } @@ -338,7 +340,7 @@ TEST_F(LayerHistoryTest, oneLayerExplicitExactVote) { EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly(Return( - Layer::FrameRate(Fps(73.4f), Layer::FrameRateCompatibility::ExactOrMultiple))); + Layer::FrameRate(73.4_Hz, Layer::FrameRateCompatibility::ExactOrMultiple))); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -352,7 +354,7 @@ TEST_F(LayerHistoryTest, oneLayerExplicitExactVote) { ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, summarizeLayerHistory(time)[0].vote); - EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate)); + EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); @@ -362,7 +364,7 @@ TEST_F(LayerHistoryTest, oneLayerExplicitExactVote) { ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, summarizeLayerHistory(time)[0].vote); - EXPECT_TRUE(Fps(73.4f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate)); + EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); } @@ -414,7 +416,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { ASSERT_EQ(2, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote); ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote); - EXPECT_TRUE(HI_FPS.equalsWithMargin(summarizeLayerHistory(time)[1].desiredRefreshRate)); + EXPECT_EQ(HI_FPS, summarizeLayerHistory(time)[1].desiredRefreshRate); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); @@ -429,7 +431,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { ASSERT_EQ(1, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); - EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate)); + EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); @@ -448,7 +450,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { ASSERT_EQ(2, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); - EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate)); + EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summary[1].vote); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(2, frequentLayerCount(time)); @@ -458,9 +460,9 @@ TEST_F(LayerHistoryTest, multipleLayers) { summary = summarizeLayerHistory(time); ASSERT_EQ(2, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); - EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate)); + EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote); - EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[1].desiredRefreshRate)); + EXPECT_EQ(HI_FPS, summary[1].desiredRefreshRate); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(2, frequentLayerCount(time)); @@ -470,9 +472,9 @@ TEST_F(LayerHistoryTest, multipleLayers) { ASSERT_EQ(2, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); - EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate)); + EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote); - EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[1].desiredRefreshRate)); + EXPECT_EQ(HI_FPS, summary[1].desiredRefreshRate); EXPECT_EQ(2, layerCount()); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(2, frequentLayerCount(time)); @@ -487,7 +489,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { ASSERT_EQ(1, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); - EXPECT_TRUE(LO_FPS.equalsWithMargin(summary[0].desiredRefreshRate)); + EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); @@ -508,7 +510,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { ASSERT_EQ(1, summary.size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); - EXPECT_TRUE(HI_FPS.equalsWithMargin(summary[0].desiredRefreshRate)); + EXPECT_EQ(HI_FPS, summary[0].desiredRefreshRate); EXPECT_EQ(1, layerCount()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); @@ -585,12 +587,12 @@ TEST_F(LayerHistoryTest, invisibleExplicitLayer) { EXPECT_CALL(*explicitVisiblelayer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*explicitVisiblelayer, getFrameRateForLayerTree()) .WillRepeatedly(Return( - Layer::FrameRate(Fps(60.0f), Layer::FrameRateCompatibility::ExactOrMultiple))); + Layer::FrameRate(60_Hz, Layer::FrameRateCompatibility::ExactOrMultiple))); EXPECT_CALL(*explicitInvisiblelayer, isVisible()).WillRepeatedly(Return(false)); EXPECT_CALL(*explicitInvisiblelayer, getFrameRateForLayerTree()) .WillRepeatedly(Return( - Layer::FrameRate(Fps(90.0f), Layer::FrameRateCompatibility::ExactOrMultiple))); + Layer::FrameRate(90_Hz, Layer::FrameRateCompatibility::ExactOrMultiple))); nsecs_t time = systemTime(); @@ -603,7 +605,7 @@ TEST_F(LayerHistoryTest, invisibleExplicitLayer) { ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, summarizeLayerHistory(time)[0].vote); - EXPECT_TRUE(Fps(60.0f).equalsWithMargin(summarizeLayerHistory(time)[0].desiredRefreshRate)); + EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(2, frequentLayerCount(time)); } @@ -661,7 +663,7 @@ TEST_F(LayerHistoryTest, heuristicLayer60Hz) { nsecs_t time = systemTime(); for (float fps = 54.0f; fps < 65.0f; fps += 0.1f) { - recordFramesAndExpect(layer, time, Fps(fps), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, Fps::fromValue(fps), 60_Hz, PRESENT_TIME_HISTORY_SIZE); } } @@ -671,13 +673,13 @@ TEST_F(LayerHistoryTest, heuristicLayer60_30Hz) { EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); nsecs_t time = systemTime(); - recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE); - recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE); - recordFramesAndExpect(layer, time, Fps(30.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE); - recordFramesAndExpect(layer, time, Fps(30.0f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE); - recordFramesAndExpect(layer, time, Fps(60.0f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE); - recordFramesAndExpect(layer, time, Fps(60.0f), Fps(60.0f), PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 30_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 30_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 60_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE); } TEST_F(LayerHistoryTest, heuristicLayerNotOscillating) { @@ -687,11 +689,11 @@ TEST_F(LayerHistoryTest, heuristicLayerNotOscillating) { nsecs_t time = systemTime(); - recordFramesAndExpect(layer, time, Fps(27.10f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE); - recordFramesAndExpect(layer, time, Fps(26.90f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE); - recordFramesAndExpect(layer, time, Fps(26.00f), Fps(24.0f), PRESENT_TIME_HISTORY_SIZE); - recordFramesAndExpect(layer, time, Fps(26.90f), Fps(24.0f), PRESENT_TIME_HISTORY_SIZE); - recordFramesAndExpect(layer, time, Fps(27.10f), Fps(30.0f), PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 26.9_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 26_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 26.9_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); } class LayerHistoryTestParameterized : public LayerHistoryTest, @@ -742,7 +744,7 @@ TEST_P(LayerHistoryTestParameterized, HeuristicLayerWithInfrequentLayer) { bool max = false; bool min = false; - Fps heuristic{0.0}; + Fps heuristic; for (const auto& layer : summarizeLayerHistory(time)) { if (layer.vote == LayerHistory::LayerVoteType::Heuristic) { heuristic = layer.desiredRefreshRate; @@ -754,7 +756,7 @@ TEST_P(LayerHistoryTestParameterized, HeuristicLayerWithInfrequentLayer) { } if (infrequentLayerUpdates > FREQUENT_LAYER_WINDOW_SIZE) { - EXPECT_TRUE(Fps(24.0f).equalsWithMargin(heuristic)); + EXPECT_EQ(24_Hz, heuristic); EXPECT_FALSE(max); if (summarizeLayerHistory(time).size() == 2) { EXPECT_TRUE(min); @@ -772,4 +774,4 @@ INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryTestParameterized, } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp index d6ce5e2ce3..f25994e399 100644 --- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp @@ -20,6 +20,7 @@ #include #include "Fps.h" +#include "FpsOps.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/LayerInfo.h" @@ -47,7 +48,7 @@ namespace { TEST_F(LayerInfoTest, prefersPresentTime) { std::deque frameTimes; - constexpr auto kExpectedFps = Fps(50.0f); + constexpr auto kExpectedFps = 50_Hz; constexpr auto kPeriod = kExpectedFps.getPeriodNsecs(); constexpr int kNumFrames = 10; for (int i = 1; i <= kNumFrames; i++) { @@ -58,14 +59,12 @@ TEST_F(LayerInfoTest, prefersPresentTime) { setFrameTimes(frameTimes); const auto averageFrameTime = calculateAverageFrameTime(); ASSERT_TRUE(averageFrameTime.has_value()); - const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime); - ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps)) - << "Expected " << averageFps << " to be equal to " << kExpectedFps; + ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime)); } TEST_F(LayerInfoTest, fallbacksToQueueTimeIfNoPresentTime) { std::deque frameTimes; - constexpr auto kExpectedFps = Fps(50.0f); + constexpr auto kExpectedFps = 50_Hz; constexpr auto kPeriod = kExpectedFps.getPeriodNsecs(); constexpr int kNumFrames = 10; for (int i = 1; i <= kNumFrames; i++) { @@ -74,17 +73,15 @@ TEST_F(LayerInfoTest, fallbacksToQueueTimeIfNoPresentTime) { .pendingModeChange = false}); } setFrameTimes(frameTimes); - setLastRefreshRate(Fps(20.0f)); // Set to some valid value + setLastRefreshRate(20_Hz); // Set to some valid value. const auto averageFrameTime = calculateAverageFrameTime(); ASSERT_TRUE(averageFrameTime.has_value()); - const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime); - ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps)) - << "Expected " << averageFps << " to be equal to " << kExpectedFps; + ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime)); } TEST_F(LayerInfoTest, returnsNulloptIfThereWasConfigChange) { std::deque frameTimesWithoutConfigChange; - const auto period = Fps(50.0f).getPeriodNsecs(); + const auto period = (50_Hz).getPeriodNsecs(); constexpr int kNumFrames = 10; for (int i = 1; i <= kNumFrames; i++) { frameTimesWithoutConfigChange.push_back(FrameTimeData{.presentTime = period * i, @@ -124,9 +121,9 @@ TEST_F(LayerInfoTest, returnsNulloptIfThereWasConfigChange) { // Make sure that this doesn't influence the calculated average FPS. TEST_F(LayerInfoTest, ignoresSmallPeriods) { std::deque frameTimes; - constexpr auto kExpectedFps = Fps(50.0f); + constexpr auto kExpectedFps = 50_Hz; constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs(); - constexpr auto kSmallPeriod = Fps(250.0f).getPeriodNsecs(); + constexpr auto kSmallPeriod = (250_Hz).getPeriodNsecs(); constexpr int kNumIterations = 10; for (int i = 1; i <= kNumIterations; i++) { frameTimes.push_back(FrameTimeData{.presentTime = kExpectedPeriod * i, @@ -141,18 +138,16 @@ TEST_F(LayerInfoTest, ignoresSmallPeriods) { setFrameTimes(frameTimes); const auto averageFrameTime = calculateAverageFrameTime(); ASSERT_TRUE(averageFrameTime.has_value()); - const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime); - ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps)) - << "Expected " << averageFps << " to be equal to " << kExpectedFps; + ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime)); } // There may be a big period of time between two frames. Make sure that // this doesn't influence the calculated average FPS. TEST_F(LayerInfoTest, ignoresLargePeriods) { std::deque frameTimes; - constexpr auto kExpectedFps = Fps(50.0f); + constexpr auto kExpectedFps = 50_Hz; constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs(); - constexpr auto kLargePeriod = Fps(9.0f).getPeriodNsecs(); + constexpr auto kLargePeriod = (9_Hz).getPeriodNsecs(); auto record = [&](nsecs_t time) { frameTimes.push_back( @@ -172,9 +167,7 @@ TEST_F(LayerInfoTest, ignoresLargePeriods) { setFrameTimes(frameTimes); const auto averageFrameTime = calculateAverageFrameTime(); ASSERT_TRUE(averageFrameTime.has_value()); - const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime); - ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps)) - << "Expected " << averageFps << " to be equal to " << kExpectedFps; + ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime)); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index a8e3e5ee6d..fc84d48b46 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -27,15 +27,13 @@ #include -#include "../../Scheduler/RefreshRateConfigs.h" #include "DisplayHardware/HWC2.h" +#include "FpsOps.h" #include "Scheduler/RefreshRateConfigs.h" using namespace std::chrono_literals; -namespace android { - -namespace scheduler { +namespace android::scheduler { namespace hal = android::hardware::graphics::composer::hal; @@ -104,33 +102,32 @@ protected: static inline const DisplayModeId HWC_CONFIG_ID_60_FRAC = DisplayModeId(10); // Test configs - DisplayModePtr mConfig60 = createDisplayMode(HWC_CONFIG_ID_60, 0, Fps(60.0f).getPeriodNsecs()); + DisplayModePtr mConfig60 = createDisplayMode(HWC_CONFIG_ID_60, 0, (60_Hz).getPeriodNsecs()); DisplayModePtr mConfig60Frac = - createDisplayMode(HWC_CONFIG_ID_60_FRAC, 0, Fps(59.94f).getPeriodNsecs()); - DisplayModePtr mConfig90 = createDisplayMode(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs()); + createDisplayMode(HWC_CONFIG_ID_60_FRAC, 0, (59.94_Hz).getPeriodNsecs()); + DisplayModePtr mConfig90 = createDisplayMode(HWC_CONFIG_ID_90, 0, (90_Hz).getPeriodNsecs()); DisplayModePtr mConfig90DifferentGroup = - createDisplayMode(HWC_CONFIG_ID_90, 1, Fps(90.0f).getPeriodNsecs()); + createDisplayMode(HWC_CONFIG_ID_90, 1, (90_Hz).getPeriodNsecs()); DisplayModePtr mConfig90DifferentResolution = - createDisplayMode(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs(), ui::Size(111, 222)); - DisplayModePtr mConfig72 = createDisplayMode(HWC_CONFIG_ID_72, 0, Fps(72.0f).getPeriodNsecs()); + createDisplayMode(HWC_CONFIG_ID_90, 0, (90_Hz).getPeriodNsecs(), ui::Size(111, 222)); + DisplayModePtr mConfig72 = createDisplayMode(HWC_CONFIG_ID_72, 0, (72_Hz).getPeriodNsecs()); DisplayModePtr mConfig72DifferentGroup = - createDisplayMode(HWC_CONFIG_ID_72, 1, Fps(72.0f).getPeriodNsecs()); - DisplayModePtr mConfig120 = - createDisplayMode(HWC_CONFIG_ID_120, 0, Fps(120.0f).getPeriodNsecs()); + createDisplayMode(HWC_CONFIG_ID_72, 1, (72_Hz).getPeriodNsecs()); + DisplayModePtr mConfig120 = createDisplayMode(HWC_CONFIG_ID_120, 0, (120_Hz).getPeriodNsecs()); DisplayModePtr mConfig120DifferentGroup = - createDisplayMode(HWC_CONFIG_ID_120, 1, Fps(120.0f).getPeriodNsecs()); - DisplayModePtr mConfig30 = createDisplayMode(HWC_CONFIG_ID_30, 0, Fps(30.0f).getPeriodNsecs()); + createDisplayMode(HWC_CONFIG_ID_120, 1, (120_Hz).getPeriodNsecs()); + DisplayModePtr mConfig30 = createDisplayMode(HWC_CONFIG_ID_30, 0, (30_Hz).getPeriodNsecs()); DisplayModePtr mConfig30DifferentGroup = - createDisplayMode(HWC_CONFIG_ID_30, 1, Fps(30.0f).getPeriodNsecs()); + createDisplayMode(HWC_CONFIG_ID_30, 1, (30_Hz).getPeriodNsecs()); DisplayModePtr mConfig30Frac = - createDisplayMode(HWC_CONFIG_ID_30_FRAC, 0, Fps(29.97f).getPeriodNsecs()); - DisplayModePtr mConfig25 = createDisplayMode(HWC_CONFIG_ID_25, 0, Fps(25.0f).getPeriodNsecs()); + createDisplayMode(HWC_CONFIG_ID_30_FRAC, 0, (29.97_Hz).getPeriodNsecs()); + DisplayModePtr mConfig25 = createDisplayMode(HWC_CONFIG_ID_25, 0, (25_Hz).getPeriodNsecs()); DisplayModePtr mConfig25DifferentGroup = - createDisplayMode(HWC_CONFIG_ID_25, 1, Fps(25.0f).getPeriodNsecs()); - DisplayModePtr mConfig50 = createDisplayMode(HWC_CONFIG_ID_50, 0, Fps(50.0f).getPeriodNsecs()); - DisplayModePtr mConfig24 = createDisplayMode(HWC_CONFIG_ID_24, 0, Fps(24.0f).getPeriodNsecs()); + createDisplayMode(HWC_CONFIG_ID_25, 1, (25_Hz).getPeriodNsecs()); + DisplayModePtr mConfig50 = createDisplayMode(HWC_CONFIG_ID_50, 0, (50_Hz).getPeriodNsecs()); + DisplayModePtr mConfig24 = createDisplayMode(HWC_CONFIG_ID_24, 0, (24_Hz).getPeriodNsecs()); DisplayModePtr mConfig24Frac = - createDisplayMode(HWC_CONFIG_ID_24_FRAC, 0, Fps(23.976f).getPeriodNsecs()); + createDisplayMode(HWC_CONFIG_ID_24_FRAC, 0, (23.976_Hz).getPeriodNsecs()); // Test device configurations // The positions of the configs in the arrays below MUST match their IDs. For example, @@ -206,9 +203,7 @@ DisplayModePtr RefreshRateConfigsTest::createDisplayMode(DisplayModeId modeId, i } namespace { -/* ------------------------------------------------------------------------ - * Test cases - */ + TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingSupported) { auto refreshRateConfigs = std::make_unique(m60OnlyConfigDevice, @@ -219,10 +214,8 @@ TEST_F(RefreshRateConfigsTest, invalidPolicy) { auto refreshRateConfigs = std::make_unique(m60OnlyConfigDevice, /*currentConfigId=*/HWC_CONFIG_ID_60); - ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({DisplayModeId(10), {Fps(60), Fps(60)}}), - 0); - ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(20), Fps(40)}}), - 0); + ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({DisplayModeId(10), {60_Hz, 60_Hz}}), 0); + ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {20_Hz, 40_Hz}}), 0); } TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) { @@ -256,8 +249,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differe ASSERT_EQ(mExpected60Config, minRate60); ASSERT_EQ(mExpected60Config, performanceRate60); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(60), Fps(90)}}), - 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60_Hz, 90_Hz}}), 0); refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90); const auto& minRate90 = getMinRefreshRateByPolicy(*refreshRateConfigs); @@ -282,8 +274,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differe ASSERT_EQ(mExpected60Config, minRate60); ASSERT_EQ(mExpected60Config, performanceRate60); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(60), Fps(90)}}), - 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60_Hz, 90_Hz}}), 0); refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90); const auto& minRate90 = getMinRefreshRateByPolicy(*refreshRateConfigs); @@ -305,8 +296,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_policyChange) { ASSERT_EQ(mExpected60Config, minRate); ASSERT_EQ(mExpected90Config, performanceRate); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}), - 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}), 0); auto minRate60 = getMinRefreshRateByPolicy(*refreshRateConfigs); auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy(); @@ -329,8 +319,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getCurrentRefreshRate) { EXPECT_EQ(current.getModeId(), HWC_CONFIG_ID_90); } - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(90), Fps(90)}}), - 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90_Hz, 90_Hz}}), 0); { auto current = refreshRateConfigs->getCurrentRefreshRate(); EXPECT_EQ(current.getModeId(), HWC_CONFIG_ID_90); @@ -344,23 +333,19 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_noLayers) { // If there are no layers we select the default frame rate, which is the max of the primary // range. - auto layers = std::vector{}; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate({}, {})); - ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}), + ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}), NO_ERROR); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate({}, {})); // We select max even when this will cause a non-seamless switch. refreshRateConfigs = std::make_unique(m60_90DeviceWithDifferentGroups, /*currentConfigId=*/HWC_CONFIG_ID_60); ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy( - {HWC_CONFIG_ID_90, /*allowGroupSwitching*/ true, {Fps(0), Fps(90)}}), + {HWC_CONFIG_ID_90, /*allowGroupSwitching*/ true, {0_Hz, 90_Hz}}), NO_ERROR); - EXPECT_EQ(mExpected90DifferentGroupConfig, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90DifferentGroupConfig, refreshRateConfigs->getBestRefreshRate({}, {})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) { @@ -368,142 +353,109 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) { std::make_unique(m60_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; lr.vote = LayerVoteType::Min; lr.name = "Min"; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.vote = LayerVoteType::Max; lr.name = "Max"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(90.0f); + lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(60.0f); + lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(45.0f); + lr.desiredRefreshRate = 45_Hz; lr.name = "45Hz Heuristic"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(30.0f); + lr.desiredRefreshRate = 30_Hz; lr.name = "30Hz Heuristic"; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(24.0f); + lr.desiredRefreshRate = 24_Hz; lr.name = "24Hz Heuristic"; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.name = ""; - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}), - 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}), 0); lr.vote = LayerVoteType::Min; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.vote = LayerVoteType::Max; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(90.0f); + lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(60.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 60_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(45.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 45_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(30.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 30_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(24.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 24_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy( - {HWC_CONFIG_ID_90, {Fps(90.0f), Fps(90.0f)}}), - 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90_Hz, 90_Hz}}), 0); lr.vote = LayerVoteType::Min; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.vote = LayerVoteType::Max; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(90.0f); + lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(60.0f); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 60_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(45.0f); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 45_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(30.0f); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 30_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(24.0f); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 24_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy( - {HWC_CONFIG_ID_60, {Fps(0.0f), Fps(120.0f)}}), - 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0_Hz, 120_Hz}}), 0); lr.vote = LayerVoteType::Min; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.vote = LayerVoteType::Max; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(90.0f); + lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(60.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 60_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(45.0f); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 45_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(30.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 30_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(24.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 24_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_multipleThreshold_60_90) { @@ -512,44 +464,37 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_multipleThreshold_60_90) { std::make_unique(m60_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60, config); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; lr.vote = LayerVoteType::Min; lr.name = "Min"; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.vote = LayerVoteType::Max; lr.name = "Max"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(90.0f); + lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(60.0f); + lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(45.0f); + lr.desiredRefreshRate = 45_Hz; lr.name = "45Hz Heuristic"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(30.0f); + lr.desiredRefreshRate = 30_Hz; lr.name = "30Hz Heuristic"; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(24.0f); + lr.desiredRefreshRate = 24_Hz; lr.name = "24Hz Heuristic"; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_72_90) { @@ -557,37 +502,30 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_72_90) { std::make_unique(m60_72_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; lr.vote = LayerVoteType::Min; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.vote = LayerVoteType::Max; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(90.0f); + lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(60.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 60_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(45.0f); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 45_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(30.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 30_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(24.0f); - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 24_Hz; + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90_120) { @@ -595,31 +533,27 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90_120) { std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}, - LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; auto& lr1 = layers[0]; auto& lr2 = layers[1]; - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = Fps(60.0f); + lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(mExpected120Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = Fps(48.0f); + lr2.desiredRefreshRate = 48_Hz; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = Fps(48.0f); + lr2.desiredRefreshRate = 48_Hz; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { @@ -627,91 +561,81 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}, - LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; auto& lr1 = layers[0]; auto& lr2 = layers[1]; - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; lr1.name = "24Hz ExplicitDefault"; - lr2.desiredRefreshRate = Fps(60.0f); + lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(mExpected120Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = Fps(60.0f); + lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(mExpected120Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = Fps(60.0f); + lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "60Hz ExplicitDefault"; - EXPECT_EQ(mExpected120Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; lr1.name = "24Hz ExplicitDefault"; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; lr1.name = "24Hz Heuristic"; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; lr1.name = "24Hz ExplicitDefault"; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.name = "90Hz ExplicitExactOrMultiple"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_multipleThreshold) { @@ -720,91 +644,81 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_mu std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/HWC_CONFIG_ID_60, config); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}, - LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; auto& lr1 = layers[0]; auto& lr2 = layers[1]; - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; lr1.name = "24Hz ExplicitDefault"; - lr2.desiredRefreshRate = Fps(60.0f); + lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(mExpected120Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = Fps(60.0f); + lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = Fps(60.0f); + lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "60Hz ExplicitDefault"; - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; lr1.name = "24Hz ExplicitDefault"; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; lr1.name = "24Hz Heuristic"; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.name = "24Hz ExplicitExactOrMultiple"; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr1.desiredRefreshRate = Fps(24.0f); + lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; lr1.name = "24Hz ExplicitDefault"; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.name = "90Hz ExplicitExactOrMultiple"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) { @@ -812,37 +726,30 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) { std::make_unique(m30_60Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; lr.vote = LayerVoteType::Min; - EXPECT_EQ(mExpected30Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.vote = LayerVoteType::Max; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(90.0f); + lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(60.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 60_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(45.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 45_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(30.0f); - EXPECT_EQ(mExpected30Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 30_Hz; + EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(24.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr.desiredRefreshRate = 24_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90) { @@ -850,60 +757,47 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90) { std::make_unique(m30_60_72_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; lr.vote = LayerVoteType::Min; lr.name = "Min"; - EXPECT_EQ(mExpected30Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.vote = LayerVoteType::Max; lr.name = "Max"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(90.0f); + lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - lr.desiredRefreshRate = Fps(60.0f); + lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true})); - lr.desiredRefreshRate = Fps(45.0f); + lr.desiredRefreshRate = 45_Hz; lr.name = "45Hz Heuristic"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true})); - lr.desiredRefreshRate = Fps(30.0f); + lr.desiredRefreshRate = 30_Hz; lr.name = "30Hz Heuristic"; - EXPECT_EQ(mExpected30Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); + EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true})); - lr.desiredRefreshRate = Fps(24.0f); + lr.desiredRefreshRate = 24_Hz; lr.name = "24Hz Heuristic"; - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true})); - lr.desiredRefreshRate = Fps(24.0f); + lr.desiredRefreshRate = 24_Hz; lr.vote = LayerVoteType::ExplicitExactOrMultiple; lr.name = "24Hz ExplicitExactOrMultiple"; - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_PriorityTest) { @@ -911,53 +805,45 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_PriorityTest) { std::make_unique(m30_60_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}, - LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; auto& lr1 = layers[0]; auto& lr2 = layers[1]; lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::Max; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = Fps(24.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr2.desiredRefreshRate = 24_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.desiredRefreshRate = Fps(24.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr2.desiredRefreshRate = 24_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr1.vote = LayerVoteType::Max; lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = Fps(60.0f); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr2.desiredRefreshRate = 60_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr1.vote = LayerVoteType::Max; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.desiredRefreshRate = Fps(60.0f); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr2.desiredRefreshRate = 60_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr1.vote = LayerVoteType::Heuristic; - lr1.desiredRefreshRate = Fps(15.0f); + lr1.desiredRefreshRate = 15_Hz; lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = Fps(45.0f); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr2.desiredRefreshRate = 45_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr1.vote = LayerVoteType::Heuristic; - lr1.desiredRefreshRate = Fps(30.0f); + lr1.desiredRefreshRate = 30_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.desiredRefreshRate = Fps(45.0f); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr2.desiredRefreshRate = 45_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo) { @@ -965,15 +851,15 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo) { std::make_unique(m60_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { - lr.desiredRefreshRate = Fps(fps); - const auto& refreshRate = - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}); - EXPECT_EQ(mExpected60Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName(); + lr.desiredRefreshRate = Fps::fromValue(fps); + const auto refreshRate = refreshRateConfigs->getBestRefreshRate(layers, {}); + EXPECT_EQ(mExpected60Config, refreshRate) + << lr.desiredRefreshRate << " chooses " << refreshRate.getName(); } } @@ -983,15 +869,15 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo_multipleThreshold_6 std::make_unique(m60_120Device, /*currentConfigId=*/HWC_CONFIG_ID_60, config); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { - lr.desiredRefreshRate = Fps(fps); - const auto& refreshRate = - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}); - EXPECT_EQ(mExpected60Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName(); + lr.desiredRefreshRate = Fps::fromValue(fps); + const auto refreshRate = refreshRateConfigs->getBestRefreshRate(layers, {}); + EXPECT_EQ(mExpected60Config, refreshRate) + << lr.desiredRefreshRate << " chooses " << refreshRate.getName(); } } @@ -1000,39 +886,35 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getBestRefreshRate_Explicit) { std::make_unique(m60_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}, - LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; auto& lr1 = layers[0]; auto& lr2 = layers[1]; lr1.vote = LayerVoteType::Heuristic; - lr1.desiredRefreshRate = Fps(60.0f); + lr1.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.desiredRefreshRate = Fps(90.0f); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr2.desiredRefreshRate = 90_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr1.vote = LayerVoteType::ExplicitDefault; - lr1.desiredRefreshRate = Fps(90.0f); + lr1.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.desiredRefreshRate = Fps(60.0f); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr2.desiredRefreshRate = 60_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr1.vote = LayerVoteType::Heuristic; - lr1.desiredRefreshRate = Fps(90.0f); + lr1.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; - lr2.desiredRefreshRate = Fps(60.0f); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + lr2.desiredRefreshRate = 60_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, testInPolicy) { - ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(Fps(60.000004f), Fps(60.000004f))); - ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(Fps(59.0f), Fps(60.1f))); - ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(Fps(75.0f), Fps(90.0f))); - ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(Fps(60.0011f), Fps(90.0f))); - ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(Fps(50.0f), Fps(59.998f))); + ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(60.000004_Hz, 60.000004_Hz)); + ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(59_Hz, 60.1_Hz)); + ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(75_Hz, 90_Hz)); + ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(60.0011_Hz, 90_Hz)); + ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(50_Hz, 59.998_Hz)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) { @@ -1040,15 +922,15 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) { std::make_unique(m60_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) { - lr.desiredRefreshRate = Fps(fps); - const auto& refreshRate = - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}); - EXPECT_EQ(mExpected90Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName(); + lr.desiredRefreshRate = Fps::fromValue(fps); + const auto refreshRate = refreshRateConfigs->getBestRefreshRate(layers, {}); + EXPECT_EQ(mExpected90Config, refreshRate) + << lr.desiredRefreshRate << " chooses " << refreshRate.getName(); } } @@ -1057,53 +939,47 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_Multiples) { std::make_unique(m60_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}, - LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; auto& lr1 = layers[0]; auto& lr2 = layers[1]; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = Fps(60.0f); + lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = Fps(60.0f); + lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::ExplicitDefault; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = Fps(60.0f); + lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = Fps(30.0f); + lr1.desiredRefreshRate = 30_Hz; lr1.name = "30Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = Fps(30.0f); + lr1.desiredRefreshRate = 30_Hz; lr1.name = "30Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) { @@ -1111,52 +987,46 @@ TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) { std::make_unique(m60_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}, - LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; auto& lr1 = layers[0]; auto& lr2 = layers[1]; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = Fps(60.0f); + lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::NoVote; lr2.name = "NoVote"; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = Fps(60.0f); + lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::NoVote; lr2.name = "NoVote"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true})); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = Fps(60.0f); + lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true})); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = Fps(60.0f); + lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); // The other layer starts to provide buffers lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = Fps(60.0f); + lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = Fps(90.0f); + lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, touchConsidered) { @@ -1165,55 +1035,50 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) { std::make_unique(m60_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false}, &consideredSignals); + refreshRateConfigs->getBestRefreshRate({}, {}, &consideredSignals); EXPECT_EQ(false, consideredSignals.touch); - refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = false}, &consideredSignals); + refreshRateConfigs->getBestRefreshRate({}, {.touch = true}, &consideredSignals); EXPECT_EQ(true, consideredSignals.touch); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}, - LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}, {.weight = 1.f}}; auto& lr1 = layers[0]; auto& lr2 = layers[1]; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = Fps(60.0f); + lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = Fps(60.0f); + lr2.desiredRefreshRate = 60_Hz; lr2.name = "60Hz Heuristic"; - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}, - &consideredSignals); + refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}, &consideredSignals); EXPECT_EQ(true, consideredSignals.touch); lr1.vote = LayerVoteType::ExplicitDefault; - lr1.desiredRefreshRate = Fps(60.0f); + lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = Fps(60.0f); + lr2.desiredRefreshRate = 60_Hz; lr2.name = "60Hz Heuristic"; - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}, - &consideredSignals); + refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}, &consideredSignals); EXPECT_EQ(false, consideredSignals.touch); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; - lr1.desiredRefreshRate = Fps(60.0f); + lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = Fps(60.0f); + lr2.desiredRefreshRate = 60_Hz; lr2.name = "60Hz Heuristic"; - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}, - &consideredSignals); + refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}, &consideredSignals); EXPECT_EQ(true, consideredSignals.touch); lr1.vote = LayerVoteType::ExplicitDefault; - lr1.desiredRefreshRate = Fps(60.0f); + lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Heuristic; - lr2.desiredRefreshRate = Fps(60.0f); + lr2.desiredRefreshRate = 60_Hz; lr2.name = "60Hz Heuristic"; - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}, - &consideredSignals); + refreshRateConfigs->getBestRefreshRate(layers, {.touch = true}, &consideredSignals); EXPECT_EQ(false, consideredSignals.touch); } @@ -1222,47 +1087,44 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitDefault) { std::make_unique(m60_90_72_120Device, /*currentConfigId=*/ HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; // Prepare a table with the vote and the expected refresh rate - const std::vector> testCases = { - {130, 120}, {120, 120}, {119, 120}, {110, 120}, + const std::initializer_list> testCases = { + {130_Hz, 120_Hz}, {120_Hz, 120_Hz}, {119_Hz, 120_Hz}, {110_Hz, 120_Hz}, - {100, 90}, {90, 90}, {89, 90}, + {100_Hz, 90_Hz}, {90_Hz, 90_Hz}, {89_Hz, 90_Hz}, - {80, 72}, {73, 72}, {72, 72}, {71, 72}, {70, 72}, + {80_Hz, 72_Hz}, {73_Hz, 72_Hz}, {72_Hz, 72_Hz}, {71_Hz, 72_Hz}, {70_Hz, 72_Hz}, - {65, 60}, {60, 60}, {59, 60}, {58, 60}, + {65_Hz, 60_Hz}, {60_Hz, 60_Hz}, {59_Hz, 60_Hz}, {58_Hz, 60_Hz}, - {55, 90}, {50, 90}, {45, 90}, + {55_Hz, 90_Hz}, {50_Hz, 90_Hz}, {45_Hz, 90_Hz}, - {42, 120}, {40, 120}, {39, 120}, + {42_Hz, 120_Hz}, {40_Hz, 120_Hz}, {39_Hz, 120_Hz}, - {37, 72}, {36, 72}, {35, 72}, + {37_Hz, 72_Hz}, {36_Hz, 72_Hz}, {35_Hz, 72_Hz}, - {30, 60}, + {30_Hz, 60_Hz}, }; - for (const auto& test : testCases) { + for (auto [desired, expected] : testCases) { lr.vote = LayerVoteType::ExplicitDefault; - lr.desiredRefreshRate = Fps(test.first); + lr.desiredRefreshRate = desired; std::stringstream ss; - ss << "ExplicitDefault " << test.first << " fps"; + ss << "ExplicitDefault " << desired; lr.name = ss.str(); - const auto& refreshRate = - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}); - EXPECT_TRUE(refreshRate.getFps().equalsWithMargin(Fps(test.second))) - << "Expecting " << test.first << "fps => " << test.second << "Hz" - << " but it was " << refreshRate.getFps(); + const auto refreshRate = refreshRateConfigs->getBestRefreshRate(layers, {}); + EXPECT_EQ(refreshRate.getFps(), expected); } } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactOrMultiple_WithFractionalRefreshRates) { - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; // Test that 23.976 will choose 24 if 23.976 is not supported @@ -1273,11 +1135,9 @@ TEST_F(RefreshRateConfigsTest, std::make_unique(modes, /*currentConfigId=*/HWC_CONFIG_ID_60); lr.vote = LayerVoteType::ExplicitExactOrMultiple; - lr.desiredRefreshRate = Fps(23.976f); - lr.name = "ExplicitExactOrMultiple 23.976 fps"; - EXPECT_EQ(HWC_CONFIG_ID_24, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + lr.desiredRefreshRate = 23.976_Hz; + lr.name = "ExplicitExactOrMultiple 23.976 Hz"; + EXPECT_EQ(HWC_CONFIG_ID_24, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } // Test that 24 will choose 23.976 if 24 is not supported @@ -1286,11 +1146,10 @@ TEST_F(RefreshRateConfigsTest, mConfig30Frac, mConfig60, mConfig60Frac}; auto refreshRateConfigs = std::make_unique(modes, /*currentConfigId=*/HWC_CONFIG_ID_60); - lr.desiredRefreshRate = Fps(24.f); - lr.name = "ExplicitExactOrMultiple 24 fps"; + lr.desiredRefreshRate = 24_Hz; + lr.name = "ExplicitExactOrMultiple 24 Hz"; EXPECT_EQ(HWC_CONFIG_ID_24_FRAC, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } // Test that 29.97 will prefer 59.94 over 60 and 30 @@ -1299,16 +1158,15 @@ TEST_F(RefreshRateConfigsTest, mConfig30, mConfig60, mConfig60Frac}; auto refreshRateConfigs = std::make_unique(modes, /*currentConfigId=*/HWC_CONFIG_ID_60); - lr.desiredRefreshRate = Fps(29.97f); - lr.name = "ExplicitExactOrMultiple 29.97f fps"; + lr.desiredRefreshRate = 29.97_Hz; + lr.name = "ExplicitExactOrMultiple 29.97 Hz"; EXPECT_EQ(HWC_CONFIG_ID_60_FRAC, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact_WithFractionalRefreshRates) { - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; // Test that voting for supported refresh rate will select this refresh rate @@ -1317,19 +1175,15 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact_WithFractionalRe std::make_unique(m24_25_30_50_60WithFracDevice, /*currentConfigId=*/HWC_CONFIG_ID_60); - for (auto desiredRefreshRate : {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f}) { + for (auto desired : {23.976_Hz, 24_Hz, 25_Hz, 29.97_Hz, 30_Hz, 50_Hz, 59.94_Hz, 60_Hz}) { lr.vote = LayerVoteType::ExplicitExact; - lr.desiredRefreshRate = Fps(desiredRefreshRate); + lr.desiredRefreshRate = desired; std::stringstream ss; - ss << "ExplicitExact " << desiredRefreshRate << " fps"; + ss << "ExplicitExact " << desired; lr.name = ss.str(); - auto selecteRefreshRate = - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}); - - EXPECT_TRUE(selecteRefreshRate.getFps().equalsWithMargin(lr.desiredRefreshRate)) - << "Expecting " << lr.desiredRefreshRate << " but it was " - << selecteRefreshRate.getFps(); + auto selectedRefreshRate = refreshRateConfigs->getBestRefreshRate(layers, {}); + EXPECT_EQ(selectedRefreshRate.getFps(), lr.desiredRefreshRate); } } @@ -1340,11 +1194,9 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact_WithFractionalRe auto refreshRateConfigs = std::make_unique(modes, /*currentConfigId=*/HWC_CONFIG_ID_60); lr.vote = LayerVoteType::ExplicitExact; - lr.desiredRefreshRate = Fps(23.976f); - lr.name = "ExplicitExact 23.976 fps"; - EXPECT_EQ(HWC_CONFIG_ID_24, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + lr.desiredRefreshRate = 23.976_Hz; + lr.name = "ExplicitExact 23.976 Hz"; + EXPECT_EQ(HWC_CONFIG_ID_24, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } // Test that 24 will choose 23.976 if 24 is not supported @@ -1353,11 +1205,10 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact_WithFractionalRe mConfig30Frac, mConfig60, mConfig60Frac}; auto refreshRateConfigs = std::make_unique(modes, /*currentConfigId=*/HWC_CONFIG_ID_60); - lr.desiredRefreshRate = Fps(24.f); - lr.name = "ExplicitExact 24 fps"; + lr.desiredRefreshRate = 24_Hz; + lr.name = "ExplicitExact 24 Hz"; EXPECT_EQ(HWC_CONFIG_ID_24_FRAC, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } } @@ -1368,15 +1219,15 @@ TEST_F(RefreshRateConfigsTest, /*currentConfigId=*/HWC_CONFIG_ID_90); ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy( - {HWC_CONFIG_ID_90, {Fps(90.f), Fps(90.f)}, {Fps(60.f), Fps(90.f)}}), + {HWC_CONFIG_ID_90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; RefreshRateConfigs::GlobalSignals consideredSignals; lr.vote = LayerVoteType::ExplicitDefault; - lr.desiredRefreshRate = Fps(60.0f); + lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz ExplicitDefault"; lr.focused = true; EXPECT_EQ(mExpected60Config, @@ -1392,18 +1243,17 @@ TEST_F(RefreshRateConfigsTest, /*currentConfigId=*/HWC_CONFIG_ID_60); ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy( - {HWC_CONFIG_ID_60, {Fps(60.f), Fps(60.f)}, {Fps(60.f), Fps(90.f)}}), + {HWC_CONFIG_ID_60, {60_Hz, 60_Hz}, {60_Hz, 90_Hz}}), 0); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; lr.vote = LayerVoteType::ExplicitDefault; - lr.desiredRefreshRate = Fps(90.0f); + lr.desiredRefreshRate = 90_Hz; lr.name = "90Hz ExplicitDefault"; lr.focused = true; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = true})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.idle = true})); } TEST_F(RefreshRateConfigsTest, @@ -1413,72 +1263,61 @@ TEST_F(RefreshRateConfigsTest, /*currentConfigId=*/HWC_CONFIG_ID_90); ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy( - {HWC_CONFIG_ID_90, {Fps(90.f), Fps(90.f)}, {Fps(60.f), Fps(90.f)}}), + {HWC_CONFIG_ID_90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0); RefreshRateConfigs::GlobalSignals consideredSignals; EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false}, - &consideredSignals)); + refreshRateConfigs->getBestRefreshRate({}, {}, &consideredSignals)); EXPECT_EQ(false, consideredSignals.touch); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& lr = layers[0]; lr.vote = LayerVoteType::ExplicitExactOrMultiple; - lr.desiredRefreshRate = Fps(60.0f); + lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz ExplicitExactOrMultiple"; lr.focused = false; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.focused = true; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.vote = LayerVoteType::ExplicitDefault; - lr.desiredRefreshRate = Fps(60.0f); + lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz ExplicitDefault"; lr.focused = false; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.focused = true; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.vote = LayerVoteType::Heuristic; - lr.desiredRefreshRate = Fps(60.0f); + lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; lr.focused = false; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.focused = true; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.vote = LayerVoteType::Max; - lr.desiredRefreshRate = Fps(60.0f); + lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Max"; lr.focused = false; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.focused = true; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.vote = LayerVoteType::Min; - lr.desiredRefreshRate = Fps(60.0f); + lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Min"; lr.focused = false; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); lr.focused = true; - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, groupSwitchingNotAllowed) { @@ -1488,17 +1327,15 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingNotAllowed) { // The default policy doesn't allow group switching. Verify that no // group switches are performed. - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& layer = layers[0]; layer.vote = LayerVoteType::ExplicitDefault; - layer.desiredRefreshRate = Fps(90.0f); + layer.desiredRefreshRate = 90_Hz; layer.seamlessness = Seamlessness::SeamedAndSeamless; layer.name = "90Hz ExplicitDefault"; layer.focused = true; - ASSERT_EQ(HWC_CONFIG_ID_60, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayer) { @@ -1510,16 +1347,14 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayer) { policy.allowGroupSwitching = true; ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& layer = layers[0]; layer.vote = LayerVoteType::ExplicitDefault; - layer.desiredRefreshRate = Fps(90.0f); + layer.desiredRefreshRate = 90_Hz; layer.seamlessness = Seamlessness::SeamedAndSeamless; layer.name = "90Hz ExplicitDefault"; layer.focused = true; - ASSERT_EQ(HWC_CONFIG_ID_90, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamless) { @@ -1532,16 +1367,14 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamless) { ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0); // Verify that we won't change the group if seamless switch is required. - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& layer = layers[0]; layer.vote = LayerVoteType::ExplicitDefault; - layer.desiredRefreshRate = Fps(90.0f); + layer.desiredRefreshRate = 90_Hz; layer.seamlessness = Seamlessness::OnlySeamless; layer.name = "90Hz ExplicitDefault"; layer.focused = true; - ASSERT_EQ(HWC_CONFIG_ID_60, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) { @@ -1556,16 +1389,14 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90); // Verify that we won't do a seamless switch if we request the same mode as the default - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& layer = layers[0]; layer.vote = LayerVoteType::ExplicitDefault; - layer.desiredRefreshRate = Fps(60.0f); + layer.desiredRefreshRate = 60_Hz; layer.seamlessness = Seamlessness::OnlySeamless; layer.name = "60Hz ExplicitDefault"; layer.focused = true; - ASSERT_EQ(HWC_CONFIG_ID_90, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerDefaultSeamlessness) { @@ -1582,17 +1413,15 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerDefaultSeamlessness) { // Verify that if the current config is in another group and there are no layers with // seamlessness=SeamedAndSeamless we'll go back to the default group. - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& layer = layers[0]; layer.vote = LayerVoteType::ExplicitDefault; - layer.desiredRefreshRate = Fps(60.0f); + layer.desiredRefreshRate = 60_Hz; layer.seamlessness = Seamlessness::Default; layer.name = "60Hz ExplicitDefault"; layer.focused = true; - ASSERT_EQ(HWC_CONFIG_ID_60, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) { @@ -1608,9 +1437,9 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) // If there's a layer with seamlessness=SeamedAndSeamless, another layer with // seamlessness=OnlySeamless can't change the mode group. - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; layers[0].vote = LayerVoteType::ExplicitDefault; - layers[0].desiredRefreshRate = Fps(60.0f); + layers[0].desiredRefreshRate = 60_Hz; layers[0].seamlessness = Seamlessness::OnlySeamless; layers[0].name = "60Hz ExplicitDefault"; layers[0].focused = true; @@ -1618,13 +1447,11 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) layers.push_back(LayerRequirement{.weight = 0.5f}); layers[1].vote = LayerVoteType::ExplicitDefault; layers[1].seamlessness = Seamlessness::SeamedAndSeamless; - layers[1].desiredRefreshRate = Fps(90.0f); + layers[1].desiredRefreshRate = 90_Hz; layers[1].name = "90Hz ExplicitDefault"; layers[1].focused = false; - ASSERT_EQ(HWC_CONFIG_ID_90, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeamed) { @@ -1644,23 +1471,21 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeame // For example, this may happen when a video playback requests and gets a seamed switch, // but another layer (with default seamlessness) starts animating. The animating layer // should not cause a seamed switch. - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; layers[0].seamlessness = Seamlessness::Default; - layers[0].desiredRefreshRate = Fps(60.0f); + layers[0].desiredRefreshRate = 60_Hz; layers[0].focused = true; layers[0].vote = LayerVoteType::ExplicitDefault; layers[0].name = "60Hz ExplicitDefault"; layers.push_back(LayerRequirement{.weight = 0.1f}); layers[1].seamlessness = Seamlessness::SeamedAndSeamless; - layers[1].desiredRefreshRate = Fps(90.0f); + layers[1].desiredRefreshRate = 90_Hz; layers[1].focused = true; layers[1].vote = LayerVoteType::ExplicitDefault; layers[1].name = "90Hz ExplicitDefault"; - ASSERT_EQ(HWC_CONFIG_ID_90, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSeamed) { @@ -1677,23 +1502,21 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSe // Layer with seamlessness=Default can change the mode group if there's a not // focused layer with seamlessness=SeamedAndSeamless. This happens for example, // when in split screen mode the user switches between the two visible applications. - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; layers[0].seamlessness = Seamlessness::Default; - layers[0].desiredRefreshRate = Fps(60.0f); + layers[0].desiredRefreshRate = 60_Hz; layers[0].focused = true; layers[0].vote = LayerVoteType::ExplicitDefault; layers[0].name = "60Hz ExplicitDefault"; layers.push_back(LayerRequirement{.weight = 0.7f}); layers[1].seamlessness = Seamlessness::SeamedAndSeamless; - layers[1].desiredRefreshRate = Fps(90.0f); + layers[1].desiredRefreshRate = 90_Hz; layers[1].focused = false; layers[1].vote = LayerVoteType::ExplicitDefault; layers[1].name = "90Hz ExplicitDefault"; - ASSERT_EQ(HWC_CONFIG_ID_60, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } TEST_F(RefreshRateConfigsTest, nonSeamlessVotePrefersSeamlessSwitches) { @@ -1707,22 +1530,18 @@ TEST_F(RefreshRateConfigsTest, nonSeamlessVotePrefersSeamlessSwitches) { policy.allowGroupSwitching = true; ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& layer = layers[0]; layer.vote = LayerVoteType::ExplicitExactOrMultiple; - layer.desiredRefreshRate = Fps(60.0f); + layer.desiredRefreshRate = 60_Hz; layer.seamlessness = Seamlessness::SeamedAndSeamless; layer.name = "60Hz ExplicitExactOrMultiple"; layer.focused = true; - ASSERT_EQ(HWC_CONFIG_ID_60, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_120); - ASSERT_EQ(HWC_CONFIG_ID_120, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + ASSERT_EQ(HWC_CONFIG_ID_120, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } TEST_F(RefreshRateConfigsTest, nonSeamlessExactAndSeamlessMultipleLayers) { @@ -1736,31 +1555,27 @@ TEST_F(RefreshRateConfigsTest, nonSeamlessExactAndSeamlessMultipleLayers) { policy.allowGroupSwitching = true; ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0); - auto layers = std::vector< - LayerRequirement>{LayerRequirement{.name = "60Hz ExplicitDefault", - .vote = LayerVoteType::ExplicitDefault, - .desiredRefreshRate = Fps(60.0f), - .seamlessness = Seamlessness::SeamedAndSeamless, - .weight = 0.5f, - .focused = false}, - LayerRequirement{.name = "25Hz ExplicitExactOrMultiple", - .vote = LayerVoteType::ExplicitExactOrMultiple, - .desiredRefreshRate = Fps(25.0f), - .seamlessness = Seamlessness::OnlySeamless, - .weight = 1.0f, - .focused = true}}; - - ASSERT_EQ(HWC_CONFIG_ID_50, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + std::vector layers = {{.name = "60Hz ExplicitDefault", + .vote = LayerVoteType::ExplicitDefault, + .desiredRefreshRate = 60_Hz, + .seamlessness = Seamlessness::SeamedAndSeamless, + .weight = 0.5f, + .focused = false}, + {.name = "25Hz ExplicitExactOrMultiple", + .vote = LayerVoteType::ExplicitExactOrMultiple, + .desiredRefreshRate = 25_Hz, + .seamlessness = Seamlessness::OnlySeamless, + .weight = 1.f, + .focused = true}}; + + ASSERT_EQ(HWC_CONFIG_ID_50, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); auto& seamedLayer = layers[0]; - seamedLayer.name = "30Hz ExplicitDefault", seamedLayer.desiredRefreshRate = Fps(30.0f); + seamedLayer.desiredRefreshRate = 30_Hz; + seamedLayer.name = "30Hz ExplicitDefault"; refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_30); - ASSERT_EQ(HWC_CONFIG_ID_25, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + ASSERT_EQ(HWC_CONFIG_ID_25, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } TEST_F(RefreshRateConfigsTest, minLayersDontTrigerSeamedSwitch) { @@ -1774,14 +1589,10 @@ TEST_F(RefreshRateConfigsTest, minLayersDontTrigerSeamedSwitch) { policy.allowGroupSwitching = true; ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0); - auto layers = std::vector{LayerRequirement{.name = "Min", - .vote = LayerVoteType::Min, - .weight = 1.f, - .focused = true}}; + std::vector layers = { + {.name = "Min", .vote = LayerVoteType::Min, .weight = 1.f, .focused = true}}; - ASSERT_EQ(HWC_CONFIG_ID_90, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) - .getModeId()); + ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {}).getModeId()); } TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) { @@ -1789,59 +1600,58 @@ TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) { std::make_unique(m30_60_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; layers[0].name = "Test layer"; + struct Args { + bool touch = false; + bool focused = true; + }; + // Return the config ID from calling getBestRefreshRate() for a single layer with the // given voteType and fps. - auto getFrameRate = [&](LayerVoteType voteType, Fps fps, bool touchActive = false, - bool focused = true) -> DisplayModeId { + auto getFrameRate = [&](LayerVoteType voteType, Fps fps, Args args = {}) -> DisplayModeId { layers[0].vote = voteType; layers[0].desiredRefreshRate = fps; - layers[0].focused = focused; - return refreshRateConfigs->getBestRefreshRate(layers, {.touch = touchActive, .idle = false}) - .getModeId(); + layers[0].focused = args.focused; + return refreshRateConfigs->getBestRefreshRate(layers, {.touch = args.touch}).getModeId(); }; ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy( - {HWC_CONFIG_ID_60, {Fps(30.f), Fps(60.f)}, {Fps(30.f), Fps(90.f)}}), + {HWC_CONFIG_ID_60, {30_Hz, 60_Hz}, {30_Hz, 90_Hz}}), 0); + EXPECT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate({}, {}).getModeId()); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90_Hz)); + EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, 90_Hz)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90_Hz)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90_Hz)); + EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz)); + + // Unfocused layers are not allowed to override primary config. EXPECT_EQ(HWC_CONFIG_ID_60, - refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false}) - .getModeId()); - EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, Fps(90.f))); - EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, Fps(90.f))); - EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, Fps(90.f))); - EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, Fps(90.f))); - EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f))); - EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f))); - - // Layers not focused are not allowed to override primary config - EXPECT_EQ(HWC_CONFIG_ID_60, - getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f), /*touch=*/false, - /*focused=*/false)); + getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz, {.focused = false})); EXPECT_EQ(HWC_CONFIG_ID_60, - getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f), /*touch=*/false, - /*focused=*/false)); + getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz, {.focused = false})); // Touch boost should be restricted to the primary range. - EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, Fps(90.f), /*touch=*/true)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90_Hz, {.touch = true})); // When we're higher than the primary range max due to a layer frame rate setting, touch boost // shouldn't drag us back down to the primary range max. EXPECT_EQ(HWC_CONFIG_ID_90, - getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f), /*touch=*/true)); + getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz, {.touch = true})); EXPECT_EQ(HWC_CONFIG_ID_60, - getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f), /*touch=*/true)); + getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz, {.touch = true})); ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy( - {HWC_CONFIG_ID_60, {Fps(60.f), Fps(60.f)}, {Fps(60.f), Fps(60.f)}}), + {HWC_CONFIG_ID_60, {60_Hz, 60_Hz}, {60_Hz, 60_Hz}}), 0); - EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, Fps(90.f))); - EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, Fps(90.f))); - EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, Fps(90.f))); - EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, Fps(90.f))); - EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, Fps(90.f))); - EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, Fps(90.f))); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90_Hz)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90_Hz)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90_Hz)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90_Hz)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, 90_Hz)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90_Hz)); } TEST_F(RefreshRateConfigsTest, idle) { @@ -1849,12 +1659,12 @@ TEST_F(RefreshRateConfigsTest, idle) { std::make_unique(m60_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; layers[0].name = "Test layer"; const auto getIdleFrameRate = [&](LayerVoteType voteType, bool touchActive) -> DisplayModeId { layers[0].vote = voteType; - layers[0].desiredRefreshRate = Fps(90.f); + layers[0].desiredRefreshRate = 90_Hz; RefreshRateConfigs::GlobalSignals consideredSignals; const auto configId = refreshRateConfigs @@ -1867,7 +1677,7 @@ TEST_F(RefreshRateConfigsTest, idle) { }; ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy( - {HWC_CONFIG_ID_60, {Fps(60.f), Fps(90.f)}, {Fps(60.f), Fps(90.f)}}), + {HWC_CONFIG_ID_60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0); // Idle should be lower priority than touch boost. @@ -1898,8 +1708,7 @@ TEST_F(RefreshRateConfigsTest, idle) { // Idle should be applied rather than the current config when there are no layers. EXPECT_EQ(HWC_CONFIG_ID_60, - refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = true}) - .getModeId()); + refreshRateConfigs->getBestRefreshRate({}, {.idle = true}).getModeId()); } TEST_F(RefreshRateConfigsTest, findClosestKnownFrameRate) { @@ -1908,23 +1717,23 @@ TEST_F(RefreshRateConfigsTest, findClosestKnownFrameRate) { /*currentConfigId=*/HWC_CONFIG_ID_60); for (float fps = 1.0f; fps <= 120.0f; fps += 0.1f) { - const auto knownFrameRate = findClosestKnownFrameRate(*refreshRateConfigs, Fps(fps)); + const auto knownFrameRate = + findClosestKnownFrameRate(*refreshRateConfigs, Fps::fromValue(fps)); Fps expectedFrameRate; if (fps < 26.91f) { - expectedFrameRate = Fps(24.0f); + expectedFrameRate = 24_Hz; } else if (fps < 37.51f) { - expectedFrameRate = Fps(30.0f); + expectedFrameRate = 30_Hz; } else if (fps < 52.51f) { - expectedFrameRate = Fps(45.0f); + expectedFrameRate = 45_Hz; } else if (fps < 66.01f) { - expectedFrameRate = Fps(60.0f); + expectedFrameRate = 60_Hz; } else if (fps < 81.01f) { - expectedFrameRate = Fps(72.0f); + expectedFrameRate = 72_Hz; } else { - expectedFrameRate = Fps(90.0f); + expectedFrameRate = 90_Hz; } - EXPECT_TRUE(expectedFrameRate.equalsWithMargin(knownFrameRate)) - << "findClosestKnownFrameRate(" << fps << ") = " << knownFrameRate; + EXPECT_EQ(expectedFrameRate, knownFrameRate); } } @@ -1933,38 +1742,32 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_KnownFrameRate) { std::make_unique(m60_90Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - struct ExpectedRate { - Fps rate; - const RefreshRate& expected; + struct Expectation { + Fps fps; + const RefreshRate& refreshRate; }; - /* clang-format off */ - std::vector knownFrameRatesExpectations = { - {Fps(24.0f), mExpected60Config}, - {Fps(30.0f), mExpected60Config}, - {Fps(45.0f), mExpected90Config}, - {Fps(60.0f), mExpected60Config}, - {Fps(72.0f), mExpected90Config}, - {Fps(90.0f), mExpected90Config}, + const std::initializer_list knownFrameRatesExpectations = { + {24_Hz, mExpected60Config}, {30_Hz, mExpected60Config}, {45_Hz, mExpected90Config}, + {60_Hz, mExpected60Config}, {72_Hz, mExpected90Config}, {90_Hz, mExpected90Config}, }; - /* clang-format on */ // Make sure the test tests all the known frame rate const auto knownFrameRateList = getKnownFrameRate(*refreshRateConfigs); - const auto equal = - std::equal(knownFrameRateList.begin(), knownFrameRateList.end(), - knownFrameRatesExpectations.begin(), - [](Fps a, const ExpectedRate& b) { return a.equalsWithMargin(b.rate); }); + const bool equal = std::equal(knownFrameRateList.begin(), knownFrameRateList.end(), + knownFrameRatesExpectations.begin(), + [](Fps fps, const Expectation& expected) { + return isApproxEqual(fps, expected.fps); + }); EXPECT_TRUE(equal); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; auto& layer = layers[0]; layer.vote = LayerVoteType::Heuristic; - for (const auto& expectedRate : knownFrameRatesExpectations) { - layer.desiredRefreshRate = expectedRate.rate; - const auto& refreshRate = - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}); - EXPECT_EQ(expectedRate.expected, refreshRate); + + for (const auto& [fps, refreshRate] : knownFrameRatesExpectations) { + layer.desiredRefreshRate = fps; + EXPECT_EQ(refreshRate, refreshRateConfigs->getBestRefreshRate(layers, {})); } } @@ -1973,40 +1776,33 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact) { std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/HWC_CONFIG_ID_60); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}, - LayerRequirement{.weight = 0.5f}}; + std::vector layers = {{.weight = 1.f}, {.weight = 0.5f}}; auto& explicitExactLayer = layers[0]; auto& explicitExactOrMultipleLayer = layers[1]; explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; - explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60); + explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz; explicitExactLayer.vote = LayerVoteType::ExplicitExact; explicitExactLayer.name = "ExplicitExact"; - explicitExactLayer.desiredRefreshRate = Fps(30); + explicitExactLayer.desiredRefreshRate = 30_Hz; - EXPECT_EQ(mExpected30Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); - EXPECT_EQ(mExpected30Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); + EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {})); + EXPECT_EQ(mExpected30Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true})); - explicitExactOrMultipleLayer.desiredRefreshRate = Fps(120); - explicitExactLayer.desiredRefreshRate = Fps(60); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz; + explicitExactLayer.desiredRefreshRate = 60_Hz; + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - explicitExactLayer.desiredRefreshRate = Fps(72); - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + explicitExactLayer.desiredRefreshRate = 72_Hz; + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - explicitExactLayer.desiredRefreshRate = Fps(90); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + explicitExactLayer.desiredRefreshRate = 90_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - explicitExactLayer.desiredRefreshRate = Fps(120); - EXPECT_EQ(mExpected120Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + explicitExactLayer.desiredRefreshRate = 120_Hz; + EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactEnableFrameRateOverride) { @@ -2015,40 +1811,33 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactEnableFrameRateOv std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/HWC_CONFIG_ID_60, config); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}, - LayerRequirement{.weight = 0.5f}}; + std::vector layers = {{.weight = 1.f}, {.weight = 0.5f}}; auto& explicitExactLayer = layers[0]; auto& explicitExactOrMultipleLayer = layers[1]; explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; - explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60); + explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz; explicitExactLayer.vote = LayerVoteType::ExplicitExact; explicitExactLayer.name = "ExplicitExact"; - explicitExactLayer.desiredRefreshRate = Fps(30); + explicitExactLayer.desiredRefreshRate = 30_Hz; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); - EXPECT_EQ(mExpected120Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); + EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true})); - explicitExactOrMultipleLayer.desiredRefreshRate = Fps(120); - explicitExactLayer.desiredRefreshRate = Fps(60); - EXPECT_EQ(mExpected120Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz; + explicitExactLayer.desiredRefreshRate = 60_Hz; + EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - explicitExactLayer.desiredRefreshRate = Fps(72); - EXPECT_EQ(mExpected72Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + explicitExactLayer.desiredRefreshRate = 72_Hz; + EXPECT_EQ(mExpected72Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - explicitExactLayer.desiredRefreshRate = Fps(90); - EXPECT_EQ(mExpected90Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + explicitExactLayer.desiredRefreshRate = 90_Hz; + EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {})); - explicitExactLayer.desiredRefreshRate = Fps(120); - EXPECT_EQ(mExpected120Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + explicitExactLayer.desiredRefreshRate = 120_Hz; + EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ReadsCached) { @@ -2059,26 +1848,20 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ReadsCached) { /*currentConfigId=*/HWC_CONFIG_ID_60); setLastBestRefreshRateInvocation(*refreshRateConfigs, - GetBestRefreshRateInvocation{.layerRequirements = std::vector< - LayerRequirement>(), - .globalSignals = {.touch = true, + GetBestRefreshRateInvocation{.globalSignals = {.touch = true, .idle = true}, .outSignalsConsidered = - {.touch = true, - .idle = false}, + {.touch = true}, .resultingBestRefreshRate = createRefreshRate( mConfig90)}); EXPECT_EQ(createRefreshRate(mConfig90), - refreshRateConfigs->getBestRefreshRate(std::vector(), - {.touch = true, .idle = true})); + refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = true})); - const GlobalSignals cachedSignalsConsidered{.touch = true, .idle = false}; + const GlobalSignals cachedSignalsConsidered{.touch = true}; setLastBestRefreshRateInvocation(*refreshRateConfigs, - GetBestRefreshRateInvocation{.layerRequirements = std::vector< - LayerRequirement>(), - .globalSignals = {.touch = true, + GetBestRefreshRateInvocation{.globalSignals = {.touch = true, .idle = true}, .outSignalsConsidered = cachedSignalsConsidered, @@ -2088,8 +1871,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ReadsCached) { GlobalSignals signalsConsidered; EXPECT_EQ(createRefreshRate(mConfig30), - refreshRateConfigs->getBestRefreshRate(std::vector(), - {.touch = true, .idle = true}, + refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = true}, &signalsConsidered)); EXPECT_EQ(cachedSignalsConsidered, signalsConsidered); @@ -2104,8 +1886,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_WritesCache) { ASSERT_FALSE(getLastBestRefreshRateInvocation(*refreshRateConfigs).has_value()); GlobalSignals globalSignals{.touch = true, .idle = true}; - auto layers = std::vector{LayerRequirement{.weight = 1.0f}, - LayerRequirement{.weight = 0.5f}}; + std::vector layers = {{.weight = 1.f}, {.weight = 0.5f}}; const auto lastResult = refreshRateConfigs->getBestRefreshRate(layers, globalSignals, /* outSignalsConsidered */ nullptr); @@ -2129,30 +1910,25 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactTouchBoost) { std::make_unique(m60_120Device, /*currentConfigId=*/HWC_CONFIG_ID_60, config); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}, - LayerRequirement{.weight = 0.5f}}; + std::vector layers = {{.weight = 1.f}, {.weight = 0.5f}}; auto& explicitExactLayer = layers[0]; auto& explicitExactOrMultipleLayer = layers[1]; explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; - explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60); + explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz; explicitExactLayer.vote = LayerVoteType::ExplicitExact; explicitExactLayer.name = "ExplicitExact"; - explicitExactLayer.desiredRefreshRate = Fps(30); + explicitExactLayer.desiredRefreshRate = 30_Hz; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); - EXPECT_EQ(mExpected120Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); + EXPECT_EQ(mExpected120Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true})); explicitExactOrMultipleLayer.vote = LayerVoteType::NoVote; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) { @@ -2161,21 +1937,19 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAn std::make_unique(m24_25_30_50_60WithFracDevice, /*currentConfigId=*/HWC_CONFIG_ID_60, config); - auto layers = std::vector{LayerRequirement{.weight = 0.5f}, - LayerRequirement{.weight = 0.5f}}; + std::vector layers = {{.weight = 0.5f}, {.weight = 0.5f}}; auto& explicitDefaultLayer = layers[0]; auto& explicitExactOrMultipleLayer = layers[1]; explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; - explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60); + explicitExactOrMultipleLayer.desiredRefreshRate = 60_Hz; explicitDefaultLayer.vote = LayerVoteType::ExplicitDefault; explicitDefaultLayer.name = "ExplicitDefault"; - explicitDefaultLayer.desiredRefreshRate = Fps(59.94f); + explicitDefaultLayer.desiredRefreshRate = 59.94_Hz; - EXPECT_EQ(mExpected60Config, - refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {})); } // b/190578904 @@ -2186,29 +1960,26 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_deviceWithCloseRefreshRates) { DisplayModes displayModes; for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { constexpr int32_t kGroup = 0; - const auto refreshRate = Fps(static_cast(fps)); + const auto refreshRate = Fps::fromValue(static_cast(fps)); displayModes.push_back( createDisplayMode(DisplayModeId(fps), kGroup, refreshRate.getPeriodNsecs())); } - const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false}; auto refreshRateConfigs = std::make_unique(displayModes, /*currentConfigId=*/displayModes[0]->getId()); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) { layers[0].desiredRefreshRate = fps; layers[0].vote = vote; EXPECT_EQ(fps.getIntValue(), - refreshRateConfigs->getBestRefreshRate(layers, globalSignals) - .getFps() - .getIntValue()) + refreshRateConfigs->getBestRefreshRate(layers, {}).getFps().getIntValue()) << "Failed for " << RefreshRateConfigs::layerVoteTypeString(vote); }; for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { - const auto refreshRate = Fps(static_cast(fps)); + const auto refreshRate = Fps::fromValue(static_cast(fps)); testRefreshRate(refreshRate, LayerVoteType::Heuristic); testRefreshRate(refreshRate, LayerVoteType::ExplicitDefault); testRefreshRate(refreshRate, LayerVoteType::ExplicitExactOrMultiple); @@ -2232,18 +2003,15 @@ TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) { EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction()); // SetPolicy(60, 90), current 60Hz => TurnOn. - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(90)}}), - 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 90_Hz}}), 0); EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction()); // SetPolicy(60, 60), current 60Hz => TurnOff - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}), - 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}), 0); EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction()); // SetPolicy(90, 90), current 90Hz => TurnOff. - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(90), Fps(90)}}), - 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90_Hz, 90_Hz}}), 0); EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction()); } @@ -2255,23 +2023,19 @@ TEST_F(RefreshRateConfigsTest, testKernelIdleTimerActionFor120Hz) { std::make_unique(m60_120Device, /*currentConfigId=*/HWC_CONFIG_ID_120); // SetPolicy(0, 60), current 60Hz => TurnOn. - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(0), Fps(60)}}), - 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0_Hz, 60_Hz}}), 0); EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction()); // SetPolicy(60, 60), current 60Hz => TurnOff. - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}), - 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 60_Hz}}), 0); EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction()); // SetPolicy(60, 120), current 60Hz => TurnOn. - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(120)}}), - 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60_Hz, 120_Hz}}), 0); EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction()); // SetPolicy(120, 120), current 120Hz => TurnOff. - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy( - {HWC_CONFIG_ID_120, {Fps(120), Fps(120)}}), + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_120, {120_Hz, 120_Hz}}), 0); EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction()); } @@ -2281,7 +2045,7 @@ TEST_F(RefreshRateConfigsTest, getFrameRateDivider) { std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/HWC_CONFIG_ID_30); - const auto frameRate = Fps(30.f); + const auto frameRate = 30_Hz; Fps displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps(); EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate)); @@ -2303,39 +2067,38 @@ TEST_F(RefreshRateConfigsTest, getFrameRateDivider) { refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90); displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps(); - EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, Fps(22.5f))); + EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, 22.5_Hz)); - EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(24.f), Fps(25.f))); - EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(24.f), Fps(23.976f))); - EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(30.f), Fps(29.97f))); - EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(60.f), Fps(59.94f))); + EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(24_Hz, 25_Hz)); + EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(24_Hz, 23.976_Hz)); + EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(30_Hz, 29.97_Hz)); + EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(60_Hz, 59.94_Hz)); } TEST_F(RefreshRateConfigsTest, isFractionalPairOrMultiple) { - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.976f), Fps(24.f))); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(23.976f))); + EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(23.976_Hz, 24_Hz)); + EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(24_Hz, 23.976_Hz)); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(30.f))); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(29.97f))); + EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(29.97_Hz, 30_Hz)); + EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(30_Hz, 29.97_Hz)); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(60.f))); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(59.94f))); + EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(59.94_Hz, 60_Hz)); + EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(60_Hz, 59.94_Hz)); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(60.f))); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(29.97f))); + EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(29.97_Hz, 60_Hz)); + EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(60_Hz, 29.97_Hz)); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(30.f))); - EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(59.94f))); + EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(59.94_Hz, 30_Hz)); + EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(30_Hz, 59.94_Hz)); - const std::vector refreshRates = {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f}; + const auto refreshRates = {23.976_Hz, 24_Hz, 25_Hz, 29.97_Hz, 30_Hz, 50_Hz, 59.94_Hz, 60_Hz}; for (auto refreshRate : refreshRates) { - EXPECT_FALSE( - RefreshRateConfigs::isFractionalPairOrMultiple(Fps(refreshRate), Fps(refreshRate))); + EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(refreshRate, refreshRate)); } - EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(25.f))); - EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.978f), Fps(25.f))); - EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(59.94f))); + EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(24_Hz, 25_Hz)); + EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(23.978_Hz, 25_Hz)); + EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(29.97_Hz, 59.94_Hz)); } TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_noLayers) { @@ -2343,9 +2106,7 @@ TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_noLayers) { std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/ HWC_CONFIG_ID_120); - auto layers = std::vector{}; - ASSERT_TRUE(refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false) - .empty()); + ASSERT_TRUE(refreshRateConfigs->getFrameRateOverrides({}, 120_Hz, {}).empty()); } TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_60on120) { @@ -2354,42 +2115,36 @@ TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_60on120) { std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/ HWC_CONFIG_ID_120, config); - auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + std::vector layers = {{.weight = 1.f}}; layers[0].name = "Test layer"; layers[0].ownerUid = 1234; - layers[0].desiredRefreshRate = Fps(60.0f); + layers[0].desiredRefreshRate = 60_Hz; layers[0].vote = LayerVoteType::ExplicitDefault; - auto frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {}); ASSERT_EQ(1, frameRateOverrides.size()); ASSERT_EQ(1, frameRateOverrides.count(1234)); - ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + ASSERT_EQ(60_Hz, frameRateOverrides.at(1234)); layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; - frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {}); ASSERT_EQ(1, frameRateOverrides.size()); ASSERT_EQ(1, frameRateOverrides.count(1234)); - ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + ASSERT_EQ(60_Hz, frameRateOverrides.at(1234)); layers[0].vote = LayerVoteType::NoVote; - frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {}); ASSERT_TRUE(frameRateOverrides.empty()); layers[0].vote = LayerVoteType::Min; - frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {}); ASSERT_TRUE(frameRateOverrides.empty()); layers[0].vote = LayerVoteType::Max; - frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {}); ASSERT_TRUE(frameRateOverrides.empty()); layers[0].vote = LayerVoteType::Heuristic; - frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {}); ASSERT_TRUE(frameRateOverrides.empty()); } @@ -2399,37 +2154,32 @@ TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_twoUids) { std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/ HWC_CONFIG_ID_120, config); - auto layers = std::vector{ - LayerRequirement{.ownerUid = 1234, .weight = 1.0f}, - LayerRequirement{.ownerUid = 5678, .weight = 1.0f}, - }; + std::vector layers = {{.ownerUid = 1234, .weight = 1.f}, + {.ownerUid = 5678, .weight = 1.f}}; layers[0].name = "Test layer 1234"; - layers[0].desiredRefreshRate = Fps(60.0f); + layers[0].desiredRefreshRate = 60_Hz; layers[0].vote = LayerVoteType::ExplicitDefault; layers[1].name = "Test layer 5678"; - layers[1].desiredRefreshRate = Fps(30.0f); + layers[1].desiredRefreshRate = 30_Hz; layers[1].vote = LayerVoteType::ExplicitDefault; - auto frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {}); ASSERT_EQ(2, frameRateOverrides.size()); ASSERT_EQ(1, frameRateOverrides.count(1234)); - ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + ASSERT_EQ(60_Hz, frameRateOverrides.at(1234)); ASSERT_EQ(1, frameRateOverrides.count(5678)); - ASSERT_EQ(30.0f, frameRateOverrides.at(5678).getValue()); + ASSERT_EQ(30_Hz, frameRateOverrides.at(5678)); layers[1].vote = LayerVoteType::Heuristic; - frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {}); ASSERT_EQ(1, frameRateOverrides.size()); ASSERT_EQ(1, frameRateOverrides.count(1234)); - ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + ASSERT_EQ(60_Hz, frameRateOverrides.at(1234)); layers[1].ownerUid = 1234; - frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {}); ASSERT_TRUE(frameRateOverrides.empty()); } @@ -2439,54 +2189,44 @@ TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_touch) { std::make_unique(m30_60_72_90_120Device, /*currentConfigId=*/ HWC_CONFIG_ID_120, config); - auto layers = std::vector{ - LayerRequirement{.ownerUid = 1234, .weight = 1.0f}, - }; - + std::vector layers = {{.ownerUid = 1234, .weight = 1.f}}; layers[0].name = "Test layer"; - layers[0].desiredRefreshRate = Fps(60.0f); + layers[0].desiredRefreshRate = 60_Hz; layers[0].vote = LayerVoteType::ExplicitDefault; - auto frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {}); ASSERT_EQ(1, frameRateOverrides.size()); ASSERT_EQ(1, frameRateOverrides.count(1234)); - ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + ASSERT_EQ(60_Hz, frameRateOverrides.at(1234)); - frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true); + frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {.touch = true}); ASSERT_EQ(1, frameRateOverrides.size()); ASSERT_EQ(1, frameRateOverrides.count(1234)); - ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + ASSERT_EQ(60_Hz, frameRateOverrides.at(1234)); layers[0].vote = LayerVoteType::ExplicitExact; - frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {}); ASSERT_EQ(1, frameRateOverrides.size()); ASSERT_EQ(1, frameRateOverrides.count(1234)); - ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + ASSERT_EQ(60_Hz, frameRateOverrides.at(1234)); - frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true); + frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {.touch = true}); ASSERT_EQ(1, frameRateOverrides.size()); ASSERT_EQ(1, frameRateOverrides.count(1234)); - ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + ASSERT_EQ(60_Hz, frameRateOverrides.at(1234)); layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; - frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/false); + frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {}); ASSERT_EQ(1, frameRateOverrides.size()); ASSERT_EQ(1, frameRateOverrides.count(1234)); - ASSERT_EQ(60.0f, frameRateOverrides.at(1234).getValue()); + ASSERT_EQ(60_Hz, frameRateOverrides.at(1234)); - frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, Fps(120.0f), /*touch=*/true); + frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(layers, 120_Hz, {.touch = true}); ASSERT_TRUE(frameRateOverrides.empty()); } } // namespace -} // namespace scheduler -} // namespace android +} // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index 0a8759de66..df4a9c46d1 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wextra" - #undef LOG_TAG #define LOG_TAG "SchedulerUnittests" @@ -35,8 +31,7 @@ using android::hardware::graphics::composer::hal::PowerMode; using testing::_; using testing::AtLeast; -namespace android { -namespace scheduler { +namespace android::scheduler { class RefreshRateStatsTest : public testing::Test { protected: @@ -88,54 +83,53 @@ DisplayModePtr RefreshRateStatsTest::createDisplayMode(DisplayModeId modeId, int } namespace { -/* ------------------------------------------------------------------------ - * Test cases - */ + TEST_F(RefreshRateStatsTest, oneConfigTest) { init({createDisplayMode(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90)}); EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); - std::unordered_map times = mRefreshRateStats->getTotalTimes(); - ASSERT_EQ(1, times.size()); - EXPECT_NE(0u, times.count("ScreenOff")); - // Setting up tests on mobile harness can be flaky with time passing, so testing for - // exact time changes can result in flaxy numbers. To avoid that remember old - // numbers to make sure the correct values are increasing in the next test. - auto screenOff = times["ScreenOff"]; + auto times = mRefreshRateStats->getTotalTimes(); + ASSERT_TRUE(times.contains("ScreenOff")); + EXPECT_EQ(1u, times.size()); // Screen is off by default. + std::chrono::milliseconds screenOff = times.get("ScreenOff")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); - EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(0u, times.count("90.00fps")); + + EXPECT_LT(screenOff, times.get("ScreenOff")->get()); + EXPECT_FALSE(times.contains("90.00 Hz")); const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps(); mRefreshRateStats->setRefreshRate(config0Fps); mRefreshRateStats->setPowerMode(PowerMode::ON); - screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; + screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); - EXPECT_EQ(screenOff, times["ScreenOff"]); - ASSERT_EQ(1u, times.count("90.00fps")); - EXPECT_LT(0, times["90.00fps"]); + + EXPECT_EQ(screenOff, times.get("ScreenOff")->get()); + ASSERT_TRUE(times.contains("90.00 Hz")); + EXPECT_LT(0ms, times.get("90.00 Hz")->get()); mRefreshRateStats->setPowerMode(PowerMode::DOZE); - auto ninety = mRefreshRateStats->getTotalTimes()["90.00fps"]; + const auto ninety = mRefreshRateStats->getTotalTimes().get("90.00 Hz")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); - EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90.00fps"]); + + EXPECT_LT(screenOff, times.get("ScreenOff")->get()); + EXPECT_EQ(ninety, times.get("90.00 Hz")->get()); mRefreshRateStats->setRefreshRate(config0Fps); - screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; + screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); + // Because the power mode is not PowerMode::ON, switching the config // does not update refresh rates that come from the config. - EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90.00fps"]); + EXPECT_LT(screenOff, times.get("ScreenOff")->get()); + EXPECT_EQ(ninety, times.get("90.00 Hz")->get()); } TEST_F(RefreshRateStatsTest, twoConfigsTest) { @@ -146,78 +140,81 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); - std::unordered_map times = mRefreshRateStats->getTotalTimes(); - ASSERT_EQ(1, times.size()); - EXPECT_NE(0u, times.count("ScreenOff")); - // Setting up tests on mobile harness can be flaky with time passing, so testing for - // exact time changes can result in flaxy numbers. To avoid that remember old - // numbers to make sure the correct values are increasing in the next test. - auto screenOff = times["ScreenOff"]; + auto times = mRefreshRateStats->getTotalTimes(); + ASSERT_TRUE(times.contains("ScreenOff")); + EXPECT_EQ(1u, times.size()); // Screen is off by default. + std::chrono::milliseconds screenOff = times.get("ScreenOff")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); - EXPECT_LT(screenOff, times["ScreenOff"]); + + EXPECT_LT(screenOff, times.get("ScreenOff")->get()); + EXPECT_FALSE(times.contains("60.00 Hz")); + EXPECT_FALSE(times.contains("90.00 Hz")); const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps(); const auto config1Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_1).getFps(); mRefreshRateStats->setRefreshRate(config0Fps); mRefreshRateStats->setPowerMode(PowerMode::ON); - screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; + screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); - EXPECT_EQ(screenOff, times["ScreenOff"]); - ASSERT_EQ(1u, times.count("90.00fps")); - EXPECT_LT(0, times["90.00fps"]); + + EXPECT_EQ(screenOff, times.get("ScreenOff")->get()); + ASSERT_TRUE(times.contains("90.00 Hz")); + EXPECT_LT(0ms, times.get("90.00 Hz")->get()); // When power mode is normal, time for configs updates. mRefreshRateStats->setRefreshRate(config1Fps); - auto ninety = mRefreshRateStats->getTotalTimes()["90.00fps"]; + auto ninety = mRefreshRateStats->getTotalTimes().get("90.00 Hz")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); - EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90.00fps"]); - ASSERT_EQ(1u, times.count("60.00fps")); - EXPECT_LT(0, times["60.00fps"]); + + EXPECT_EQ(screenOff, times.get("ScreenOff")->get()); + EXPECT_EQ(ninety, times.get("90.00 Hz")->get()); + ASSERT_TRUE(times.contains("60.00 Hz")); + EXPECT_LT(0ms, times.get("60.00 Hz")->get()); mRefreshRateStats->setRefreshRate(config0Fps); - auto sixty = mRefreshRateStats->getTotalTimes()["60.00fps"]; + auto sixty = mRefreshRateStats->getTotalTimes().get("60.00 Hz")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); - EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_LT(ninety, times["90.00fps"]); - EXPECT_EQ(sixty, times["60.00fps"]); + + EXPECT_EQ(screenOff, times.get("ScreenOff")->get()); + EXPECT_LT(ninety, times.get("90.00 Hz")->get()); + EXPECT_EQ(sixty, times.get("60.00 Hz")->get()); mRefreshRateStats->setRefreshRate(config1Fps); - ninety = mRefreshRateStats->getTotalTimes()["90.00fps"]; + ninety = mRefreshRateStats->getTotalTimes().get("90.00 Hz")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); - EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90.00fps"]); - EXPECT_LT(sixty, times["60.00fps"]); + + EXPECT_EQ(screenOff, times.get("ScreenOff")->get()); + EXPECT_EQ(ninety, times.get("90.00 Hz")->get()); + EXPECT_LT(sixty, times.get("60.00 Hz")->get()); // Because the power mode is not PowerMode::ON, switching the config // does not update refresh rates that come from the config. mRefreshRateStats->setPowerMode(PowerMode::DOZE); mRefreshRateStats->setRefreshRate(config0Fps); - sixty = mRefreshRateStats->getTotalTimes()["60.00fps"]; + sixty = mRefreshRateStats->getTotalTimes().get("60.00 Hz")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); - EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90.00fps"]); - EXPECT_EQ(sixty, times["60.00fps"]); + + EXPECT_LT(screenOff, times.get("ScreenOff")->get()); + EXPECT_EQ(ninety, times.get("90.00 Hz")->get()); + EXPECT_EQ(sixty, times.get("60.00 Hz")->get()); mRefreshRateStats->setRefreshRate(config1Fps); - screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; + screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); - EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90.00fps"]); - EXPECT_EQ(sixty, times["60.00fps"]); + + EXPECT_LT(screenOff, times.get("ScreenOff")->get()); + EXPECT_EQ(ninety, times.get("90.00 Hz")->get()); + EXPECT_EQ(sixty, times.get("60.00 Hz")->get()); } -} // namespace -} // namespace scheduler -} // namespace android -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" +} // namespace +} // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index e2b3993211..599b235ff2 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -54,13 +54,13 @@ protected: const DisplayModePtr mode60 = DisplayMode::Builder(0) .setId(DisplayModeId(0)) .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) - .setVsyncPeriod(Fps(60.f).getPeriodNsecs()) + .setVsyncPeriod((60_Hz).getPeriodNsecs()) .setGroup(0) .build(); const DisplayModePtr mode120 = DisplayMode::Builder(1) .setId(DisplayModeId(1)) .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) - .setVsyncPeriod(Fps(120.f).getPeriodNsecs()) + .setVsyncPeriod((120_Hz).getPeriodNsecs()) .setGroup(0) .build(); @@ -217,17 +217,17 @@ TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) { } TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) { - EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 30ms)); - EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(Fps(90), 30ms)); - EXPECT_EQ(3, mFlinger.calculateMaxAcquiredBufferCount(Fps(120), 30ms)); + EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 30ms)); + EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(90_Hz, 30ms)); + EXPECT_EQ(3, mFlinger.calculateMaxAcquiredBufferCount(120_Hz, 30ms)); - EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 40ms)); + EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 40ms)); - EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(Fps(60), 10ms)); + EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms)); } MATCHER(Is120Hz, "") { - return arg.getFps().equalsWithMargin(Fps(120.f)); + return isApproxEqual(arg.getFps(), 120_Hz); } TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 6c3b2fdc6c..3b409658d7 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -29,6 +29,7 @@ #include "Layer.h" // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" +#include "FpsOps.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/MockEventThread.h" @@ -96,12 +97,11 @@ std::string PrintToStringParamName( */ class SetFrameRateTest : public ::testing::TestWithParam> { protected: - const FrameRate FRAME_RATE_VOTE1 = FrameRate(Fps(67.f), FrameRateCompatibility::Default); - const FrameRate FRAME_RATE_VOTE2 = - FrameRate(Fps(14.f), FrameRateCompatibility::ExactOrMultiple); - const FrameRate FRAME_RATE_VOTE3 = FrameRate(Fps(99.f), FrameRateCompatibility::NoVote); - const FrameRate FRAME_RATE_TREE = FrameRate(Fps(0.f), FrameRateCompatibility::NoVote); - const FrameRate FRAME_RATE_NO_VOTE = FrameRate(Fps(0.f), FrameRateCompatibility::Default); + const FrameRate FRAME_RATE_VOTE1 = FrameRate(67_Hz, FrameRateCompatibility::Default); + const FrameRate FRAME_RATE_VOTE2 = FrameRate(14_Hz, FrameRateCompatibility::ExactOrMultiple); + const FrameRate FRAME_RATE_VOTE3 = FrameRate(99_Hz, FrameRateCompatibility::NoVote); + const FrameRate FRAME_RATE_TREE = FrameRate(Fps(), FrameRateCompatibility::NoVote); + const FrameRate FRAME_RATE_NO_VOTE = FrameRate(Fps(), FrameRateCompatibility::Default); SetFrameRateTest(); @@ -172,9 +172,7 @@ void SetFrameRateTest::setupScheduler() { } namespace { -/* ------------------------------------------------------------------------ - * Test cases - */ + TEST_P(SetFrameRateTest, SetAndGet) { EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); @@ -470,8 +468,8 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { .mutableLayerHistory() ->summarize(*mFlinger.mutableScheduler().refreshRateConfigs(), 0); ASSERT_EQ(2u, layerHistorySummary.size()); - EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[0].desiredRefreshRate)); - EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[1].desiredRefreshRate)); + EXPECT_EQ(FRAME_RATE_VOTE1.rate, layerHistorySummary[0].desiredRefreshRate); + EXPECT_EQ(FRAME_RATE_VOTE1.rate, layerHistorySummary[1].desiredRefreshRate); } TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) { diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index 317cdf1592..1487a962f9 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -64,16 +64,14 @@ using SurfaceflingerStatsLayerInfoWrapper = #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)); +const constexpr Fps kRefreshRate0 = 61_Hz; +const constexpr Fps kRenderRate0 = 31_Hz; static constexpr int32_t kGameMode = TimeStatsHelper::GameModeUnsupported; enum InputCommand : int32_t { @@ -1498,14 +1496,14 @@ TEST_F(TimeStatsTest, refreshRateIsClampedToNearestBucket) { EXPECT_THAT(result, HasSubstr(expectedResult)) << "failed for " << fps; }; - verifyRefreshRateBucket(Fps(91.f), 90); - verifyRefreshRateBucket(Fps(89.f), 90); + verifyRefreshRateBucket(91_Hz, 90); + verifyRefreshRateBucket(89_Hz, 90); - verifyRefreshRateBucket(Fps(61.f), 60); - verifyRefreshRateBucket(Fps(59.f), 60); + verifyRefreshRateBucket(61_Hz, 60); + verifyRefreshRateBucket(59_Hz, 60); - verifyRefreshRateBucket(Fps(31.f), 30); - verifyRefreshRateBucket(Fps(29.f), 30); + verifyRefreshRateBucket(31_Hz, 30); + verifyRefreshRateBucket(29_Hz, 30); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index 2b5b7b5a5b..bf69704210 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -344,7 +344,7 @@ public: // Both the droppedSurfaceFrame and presentedSurfaceFrame should be in // pendingJankClassifications. EXPECT_EQ(2u, layer->mPendingJankClassifications.size()); - presentedSurfaceFrame->onPresent(20, JankType::None, Fps::fromPeriodNsecs(11), + presentedSurfaceFrame->onPresent(20, JankType::None, 90_Hz, /*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0); layer->releasePendingBuffer(25); @@ -462,10 +462,10 @@ public: // BufferlessSurfaceFrames are immediately set to presented and added to the DisplayFrame. // Since we don't have access to DisplayFrame here, trigger an onPresent directly. for (auto& surfaceFrame : bufferlessSurfaceFrames) { - surfaceFrame->onPresent(20, JankType::None, Fps::fromPeriodNsecs(11), + surfaceFrame->onPresent(20, JankType::None, 90_Hz, /*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0); } - presentedBufferSurfaceFrame->onPresent(20, JankType::None, Fps::fromPeriodNsecs(11), + presentedBufferSurfaceFrame->onPresent(20, JankType::None, 90_Hz, /*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0); diff --git a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp index 41a4d308ce..21ee071f1b 100644 --- a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp +++ b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp @@ -44,7 +44,7 @@ public: class WorkDurationTest : public testing::Test { protected: WorkDurationTest() - : mWorkDuration(Fps(60.0f), 10'500'000, 20'500'000, 16'000'000, 16'500'000, 13'500'000, + : mWorkDuration(60_Hz, 10'500'000, 20'500'000, 16'000'000, 16'500'000, 13'500'000, 21'000'000, 1234) {} ~WorkDurationTest() = default; @@ -56,9 +56,9 @@ protected: * Test cases */ TEST_F(WorkDurationTest, getConfigsForRefreshRate_60Hz) { - mWorkDuration.setRefreshRateFps(Fps(60.0f)); + mWorkDuration.setRefreshRateFps(60_Hz); auto currentOffsets = mWorkDuration.getCurrentConfigs(); - auto offsets = mWorkDuration.getConfigsForRefreshRate(Fps(60.0f)); + auto offsets = mWorkDuration.getConfigsForRefreshRate(60_Hz); EXPECT_EQ(currentOffsets, offsets); EXPECT_EQ(offsets.late.sfOffset, 6'166'667); @@ -81,9 +81,9 @@ TEST_F(WorkDurationTest, getConfigsForRefreshRate_60Hz) { } TEST_F(WorkDurationTest, getConfigsForRefreshRate_90Hz) { - mWorkDuration.setRefreshRateFps(Fps(90.0f)); + mWorkDuration.setRefreshRateFps(90_Hz); auto currentOffsets = mWorkDuration.getCurrentConfigs(); - auto offsets = mWorkDuration.getConfigsForRefreshRate(Fps(90.0f)); + auto offsets = mWorkDuration.getConfigsForRefreshRate(90_Hz); EXPECT_EQ(currentOffsets, offsets); EXPECT_EQ(offsets.late.sfOffset, 611'111); @@ -106,7 +106,7 @@ TEST_F(WorkDurationTest, getConfigsForRefreshRate_90Hz) { } TEST_F(WorkDurationTest, getConfigsForRefreshRate_DefaultOffsets) { - TestableWorkDuration phaseOffsetsWithDefaultValues(Fps(60.0f), -1, -1, -1, -1, -1, -1, 0); + TestableWorkDuration phaseOffsetsWithDefaultValues(60_Hz, -1, -1, -1, -1, -1, -1, 0); auto validateOffsets = [](const auto& offsets, std::chrono::nanoseconds vsyncPeriod) { EXPECT_EQ(offsets.late.sfOffset, 1'000'000); @@ -138,12 +138,12 @@ TEST_F(WorkDurationTest, getConfigsForRefreshRate_DefaultOffsets) { validateOffsets(offsets, std::chrono::nanoseconds(refreshRate.getPeriodNsecs())); }; - testForRefreshRate(Fps(90.0f)); - testForRefreshRate(Fps(60.0f)); + testForRefreshRate(90_Hz); + testForRefreshRate(60_Hz); } TEST_F(WorkDurationTest, getConfigsForRefreshRate_unknownRefreshRate) { - auto offsets = mWorkDuration.getConfigsForRefreshRate(Fps(14.7f)); + auto offsets = mWorkDuration.getConfigsForRefreshRate(14.7_Hz); EXPECT_EQ(offsets.late.sfOffset, 57'527'208); EXPECT_EQ(offsets.late.appOffset, 37'027'208); @@ -181,13 +181,12 @@ public: std::optional highFpsEarlyAppOffsetNs, std::optional highFpsEarlyGpuAppOffsetNs, nsecs_t thresholdForNextVsync, nsecs_t hwcMinWorkDuration) - : impl::PhaseOffsets(Fps(60.0f), vsyncPhaseOffsetNs, sfVSyncPhaseOffsetNs, - earlySfOffsetNs, earlyGpuSfOffsetNs, earlyAppOffsetNs, - earlyGpuAppOffsetNs, highFpsVsyncPhaseOffsetNs, - highFpsSfVSyncPhaseOffsetNs, highFpsEarlySfOffsetNs, - highFpsEarlyGpuSfOffsetNs, highFpsEarlyAppOffsetNs, - highFpsEarlyGpuAppOffsetNs, thresholdForNextVsync, - hwcMinWorkDuration) {} + : impl::PhaseOffsets(60_Hz, vsyncPhaseOffsetNs, sfVSyncPhaseOffsetNs, earlySfOffsetNs, + earlyGpuSfOffsetNs, earlyAppOffsetNs, earlyGpuAppOffsetNs, + highFpsVsyncPhaseOffsetNs, highFpsSfVSyncPhaseOffsetNs, + highFpsEarlySfOffsetNs, highFpsEarlyGpuSfOffsetNs, + highFpsEarlyAppOffsetNs, highFpsEarlyGpuAppOffsetNs, + thresholdForNextVsync, hwcMinWorkDuration) {} }; class PhaseOffsetsTest : public testing::Test { @@ -201,7 +200,7 @@ protected: }; TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_unknownRefreshRate) { - auto offsets = mPhaseOffsets.getConfigsForRefreshRate(Fps(14.7f)); + auto offsets = mPhaseOffsets.getConfigsForRefreshRate(14.7_Hz); EXPECT_EQ(offsets.late.sfOffset, 6'000'000); EXPECT_EQ(offsets.late.appOffset, 2'000'000); @@ -223,7 +222,7 @@ TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_unknownRefreshRate) { } TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_60Hz) { - auto offsets = mPhaseOffsets.getConfigsForRefreshRate(Fps(60.0f)); + auto offsets = mPhaseOffsets.getConfigsForRefreshRate(60_Hz); EXPECT_EQ(offsets.late.sfOffset, 6'000'000); EXPECT_EQ(offsets.late.appOffset, 2'000'000); @@ -245,7 +244,7 @@ TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_60Hz) { } TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_90Hz) { - auto offsets = mPhaseOffsets.getConfigsForRefreshRate(Fps(90.0f)); + auto offsets = mPhaseOffsets.getConfigsForRefreshRate(90_Hz); EXPECT_EQ(offsets.late.sfOffset, 1'000'000); EXPECT_EQ(offsets.late.appOffset, 2'000'000); @@ -269,7 +268,7 @@ TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_90Hz) { TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_DefaultValues_60Hz) { TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {}, 2'000'000, 1'000'000, {}, {}, {}, {}, 10'000'000, 1234}; - auto offsets = phaseOffsets.getConfigsForRefreshRate(Fps(60.0f)); + auto offsets = phaseOffsets.getConfigsForRefreshRate(60_Hz); EXPECT_EQ(offsets.late.sfOffset, 1'000'000); EXPECT_EQ(offsets.late.appOffset, 1'000'000); @@ -293,7 +292,7 @@ TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_DefaultValues_60Hz) { TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_DefaultValues_90Hz) { TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {}, 2'000'000, 1'000'000, {}, {}, {}, {}, 10'000'000, 1234}; - auto offsets = phaseOffsets.getConfigsForRefreshRate(Fps(90.0f)); + auto offsets = phaseOffsets.getConfigsForRefreshRate(90_Hz); EXPECT_EQ(offsets.late.sfOffset, 1'000'000); EXPECT_EQ(offsets.late.appOffset, 2'000'000); -- cgit v1.2.3-59-g8ed1b From 23e07500a900bed481d87f0118392966244f36b8 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Fri, 15 Oct 2021 11:58:19 +0000 Subject: Compute unique layer name in with sequence Remove 'getUniqueLayerName' so we could remove stack lock from 'createLayer'. Bug: 202621651 Test: atest libsurfaceflinger_unittest Test: atest SurfaceFlinger_test Change-Id: If5f4386b6da99bd540231b0c197c59a5823d7d4a --- services/surfaceflinger/Layer.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 39 ++++------------------ services/surfaceflinger/SurfaceFlinger.h | 2 -- .../tests/SurfaceInterceptor_test.cpp | 22 ++++++------ 4 files changed, 20 insertions(+), 45 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 68ca2f08ad..3b98d500cf 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -88,7 +88,7 @@ std::atomic Layer::sSequence{1}; Layer::Layer(const LayerCreationArgs& args) : mFlinger(args.flinger), - mName(args.name), + mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)), mClientRef(args.client), mWindowType( static_cast(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5f4acc9cc5..e565bbb2b8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4209,7 +4209,7 @@ status_t SurfaceFlinger::mirrorLayer(const sp& client, const sp sp mirrorLayer; sp mirrorFrom; - std::string uniqueName = getUniqueLayerName("MirrorRoot"); + std::string layerName = "MirrorRoot"; { Mutex::Autolock _l(mStateLock); @@ -4218,7 +4218,7 @@ status_t SurfaceFlinger::mirrorLayer(const sp& client, const sp return NAME_NOT_FOUND; } - status_t result = createContainerLayer(client, std::move(uniqueName), -1, -1, 0, + status_t result = createContainerLayer(client, std::move(layerName), -1, -1, 0, LayerMetadata(), outHandle, &mirrorLayer); if (result != NO_ERROR) { return result; @@ -4252,12 +4252,12 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie sp layer; - std::string uniqueName = getUniqueLayerName(name.string()); + std::string layerName{name.string()}; switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceBufferQueue: case ISurfaceComposerClient::eFXSurfaceBufferState: { - result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags, + result = createBufferStateLayer(client, std::move(layerName), w, h, flags, std::move(metadata), handle, &layer); std::atomic* pendingBufferCounter = layer->getPendingBufferCounter(); if (pendingBufferCounter) { @@ -4274,7 +4274,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie return BAD_VALUE; } - result = createEffectLayer(client, std::move(uniqueName), w, h, flags, + result = createEffectLayer(client, std::move(layerName), w, h, flags, std::move(metadata), handle, &layer); break; case ISurfaceComposerClient::eFXSurfaceContainer: @@ -4284,7 +4284,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie int(w), int(h)); return BAD_VALUE; } - result = createContainerLayer(client, std::move(uniqueName), w, h, flags, + result = createContainerLayer(client, std::move(layerName), w, h, flags, std::move(metadata), handle, &layer); break; default: @@ -4302,38 +4302,12 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie if (result != NO_ERROR) { return result; } - mInterceptor->saveSurfaceCreation(layer); setTransactionFlags(eTransactionNeeded); *outLayerId = layer->sequence; return result; } -std::string SurfaceFlinger::getUniqueLayerName(const char* name) { - unsigned dupeCounter = 0; - - // Tack on our counter whether there is a hit or not, so everyone gets a tag - std::string uniqueName = base::StringPrintf("%s#%u", name, dupeCounter); - - // Grab the state lock since we're accessing mCurrentState - Mutex::Autolock lock(mStateLock); - - // Loop over layers until we're sure there is no matching name - bool matchFound = true; - while (matchFound) { - matchFound = false; - mCurrentState.traverse([&](Layer* layer) { - if (layer->getName() == uniqueName) { - matchFound = true; - uniqueName = base::StringPrintf("%s#%u", name, ++dupeCounter); - } - }); - } - - ALOGV_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name, uniqueName.c_str()); - return uniqueName; -} - status_t SurfaceFlinger::createBufferQueueLayer(const sp& client, std::string name, uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata, PixelFormat& format, @@ -6885,6 +6859,7 @@ sp SurfaceFlinger::handleLayerCreatedLocked(const sp& handle) { } } + mInterceptor->saveSurfaceCreation(layer); return layer; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index feee5dfcd7..276c7f6bfe 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -786,8 +786,6 @@ private: status_t mirrorLayer(const sp& client, const sp& mirrorFromHandle, sp* outHandle, int32_t* outLayerId); - std::string getUniqueLayerName(const char* name); - // called when all clients have released all their references to // this layer meaning it is entirely safe to destroy all // resources associated to this layer. diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index ee16f40b6d..2082c42001 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -19,6 +19,7 @@ #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wextra" +#include #include #include #include @@ -56,10 +57,7 @@ std::vector BLUR_REGIONS_UPDATE; const String8 DISPLAY_NAME("SurfaceInterceptor Display Test"); constexpr auto TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface"; constexpr auto TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface"; -constexpr auto UNIQUE_TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface#0"; -constexpr auto UNIQUE_TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface#0"; constexpr auto LAYER_NAME = "Layer Create and Delete Test"; -constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0"; constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.winscope"; @@ -105,11 +103,15 @@ static void disableInterceptor() { system("service call SurfaceFlinger 1020 i32 0 > /dev/null"); } +std::string getUniqueName(const std::string& name, const Increment& increment) { + return base::StringPrintf("%s#%d", name.c_str(), increment.surface_creation().id()); +} + int32_t getSurfaceId(const Trace& capturedTrace, const std::string& surfaceName) { int32_t layerId = 0; for (const auto& increment : capturedTrace.increment()) { if (increment.increment_case() == increment.kSurfaceCreation) { - if (increment.surface_creation().name() == surfaceName) { + if (increment.surface_creation().name() == getUniqueName(surfaceName, increment)) { layerId = increment.surface_creation().id(); } } @@ -293,8 +295,8 @@ void SurfaceInterceptorTest::setupBackgroundSurface() { } void SurfaceInterceptorTest::preProcessTrace(const Trace& trace) { - mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_BG_SURFACE_NAME); - mFGLayerId = getSurfaceId(trace, UNIQUE_TEST_FG_SURFACE_NAME); + mBGLayerId = getSurfaceId(trace, TEST_BG_SURFACE_NAME); + mFGLayerId = getSurfaceId(trace, TEST_FG_SURFACE_NAME); } void SurfaceInterceptorTest::captureTest(TestTransactionAction action, @@ -752,9 +754,9 @@ void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) { } bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) { - bool isMatch(increment.surface_creation().name() == UNIQUE_LAYER_NAME && - increment.surface_creation().w() == SIZE_UPDATE && - increment.surface_creation().h() == SIZE_UPDATE); + bool isMatch(increment.surface_creation().name() == getUniqueName(LAYER_NAME, increment) && + increment.surface_creation().w() == SIZE_UPDATE && + increment.surface_creation().h() == SIZE_UPDATE); if (isMatch && !foundSurface) { foundSurface = true; } else if (isMatch && foundSurface) { @@ -808,7 +810,7 @@ bool SurfaceInterceptorTest::singleIncrementFound(const Trace& trace, break; case Increment::IncrementCase::kSurfaceDeletion: // Find the id of created surface. - targetId = getSurfaceId(trace, UNIQUE_LAYER_NAME); + targetId = getSurfaceId(trace, LAYER_NAME); foundIncrement = surfaceDeletionFound(increment, targetId, foundIncrement); break; case Increment::IncrementCase::kDisplayCreation: -- cgit v1.2.3-59-g8ed1b From c6d2d2b11684f6d306ef0fd12c909b185158e889 Mon Sep 17 00:00:00 2001 From: Rob Carr Date: Mon, 25 Oct 2021 16:51:49 +0000 Subject: Revert "Layer: Use raw pointers for Current/Drawing parent" This reverts commit cbdb79a195e6c690e16948a7e7c3abbd36414b17. Bug: 203175614 Bug: 203559094 Change-Id: I5432ad46bfbbe5a009e3fb72ae7ac129263260ce --- services/surfaceflinger/BufferLayer.cpp | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 2 +- services/surfaceflinger/Layer.cpp | 77 ++++++++++------------ services/surfaceflinger/Layer.h | 6 +- services/surfaceflinger/SurfaceFlinger.cpp | 7 +- .../tests/unittests/TestableSurfaceFlinger.h | 2 +- 6 files changed, 42 insertions(+), 54 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 82c91e7d30..8de43e0fe6 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -223,7 +223,7 @@ std::optional BufferLayer::prepareCli * of a camera where the buffer remains in native orientation, * we want the pixels to always be upright. */ - auto p = mDrawingParent; + sp p = mDrawingParent.promote(); if (p != nullptr) { const auto parentTransform = p->getTransform(); tr = tr * inverseOrientation(parentTransform.getOrientation()); diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index ba193c3be2..4eeaba154f 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -989,7 +989,7 @@ void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) { * how to go from screen space back to window space. */ ui::Transform BufferStateLayer::getInputTransform() const { - auto parent = mDrawingParent; + sp parent = mDrawingParent.promote(); if (parent == nullptr) { return ui::Transform(); } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5707c67a56..4f4a897084 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -179,23 +179,9 @@ Layer::~Layer() { if (mDrawingState.sidebandStream != nullptr) { mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount(); } - if (mHadClonedChild) { mFlinger->mNumClones--; } - - for (auto const& child : mCurrentChildren) { - if (child->mCurrentParent == this) child->mCurrentParent = nullptr; - if (child->mDrawingParent == this) { - child->mDrawingParent = nullptr; - } - } - for (auto const& child : mDrawingChildren) { - if (child->mCurrentParent == this) child->mCurrentParent = nullptr; - if (child->mDrawingParent == this) { - child->mDrawingParent = nullptr; - } - } } LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp client, std::string name, @@ -251,7 +237,7 @@ void Layer::removeFromCurrentState() { } sp Layer::getRootLayer() { - auto parent = getParent(); + sp parent = getParent(); if (parent == nullptr) { return this; } @@ -676,7 +662,7 @@ bool Layer::isSecure() const { return true; } - const auto p = mDrawingParent; + const auto p = mDrawingParent.promote(); return (p != nullptr) ? p->isSecure() : false; } @@ -859,7 +845,7 @@ bool Layer::isTrustedOverlay() const { if (getDrawingState().isTrustedOverlay) { return true; } - const auto p = mDrawingParent; + const auto& p = mDrawingParent.promote(); return (p != nullptr) && p->isTrustedOverlay(); } @@ -1039,7 +1025,7 @@ int32_t Layer::getFrameRateSelectionPriority() const { return mDrawingState.frameRateSelectionPriority; } // If not, search whether its parents have it set. - auto parent = getParent(); + sp parent = getParent(); if (parent != nullptr) { return parent->getFrameRateSelectionPriority(); } @@ -1052,11 +1038,10 @@ bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) { }; ui::LayerStack Layer::getLayerStack() const { - auto p = mDrawingParent; - if (p == nullptr) { - return getDrawingState().layerStack; + if (const auto parent = mDrawingParent.promote()) { + return parent->getLayerStack(); } - return mDrawingParent->getLayerStack(); + return getDrawingState().layerStack; } bool Layer::setShadowRadius(float shadowRadius) { @@ -1101,7 +1086,7 @@ StretchEffect Layer::getStretchEffect() const { return mDrawingState.stretchEffect; } - auto parent = mDrawingParent; + sp parent = getParent(); if (parent != nullptr) { auto effect = parent->getStretchEffect(); if (effect.hasEffect()) { @@ -1316,7 +1301,7 @@ Layer::FrameRate Layer::getFrameRateForLayerTree() const { bool Layer::isHiddenByPolicy() const { const State& s(mDrawingState); - auto parent = mDrawingParent; + const auto& parent = mDrawingParent.promote(); if (parent != nullptr && parent->isHiddenByPolicy()) { return true; } @@ -1363,7 +1348,7 @@ LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const { LayerDebugInfo info; const State& ds = getDrawingState(); info.mName = getName(); - auto parent = mDrawingParent; + sp parent = mDrawingParent.promote(); info.mParentName = parent ? parent->getName() : "none"s; info.mType = getType(); info.mTransparentRegion = ds.activeTransparentRegion_legacy; @@ -1595,7 +1580,7 @@ ssize_t Layer::removeChild(const sp& layer) { void Layer::setChildrenDrawingParent(const sp& newParent) { for (const sp& child : mDrawingChildren) { - child->mDrawingParent = newParent.get(); + child->mDrawingParent = newParent; child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform, newParent->mEffectiveShadowRadius); } @@ -1615,7 +1600,7 @@ bool Layer::reparent(const sp& newParentHandle) { } } - auto parent = getParent(); + sp parent = getParent(); if (parent != nullptr) { parent->removeChild(this); } @@ -1650,7 +1635,7 @@ bool Layer::setColorTransform(const mat4& matrix) { mat4 Layer::getColorTransform() const { mat4 colorTransform = mat4(getDrawingState().colorTransform); - if (auto parent = mDrawingParent; parent != nullptr) { + if (sp parent = mDrawingParent.promote(); parent != nullptr) { colorTransform = parent->getColorTransform() * colorTransform; } return colorTransform; @@ -1658,7 +1643,7 @@ mat4 Layer::getColorTransform() const { bool Layer::hasColorTransform() const { bool hasColorTransform = getDrawingState().hasColorTransform; - if (auto parent = mDrawingParent; parent != nullptr) { + if (sp parent = mDrawingParent.promote(); parent != nullptr) { hasColorTransform = hasColorTransform || parent->hasColorTransform(); } return hasColorTransform; @@ -1672,7 +1657,7 @@ bool Layer::isLegacyDataSpace() const { } void Layer::setParent(const sp& layer) { - mCurrentParent = layer.get(); + mCurrentParent = layer; } int32_t Layer::getZ(LayerVector::StateSet) const { @@ -1876,7 +1861,7 @@ ui::Transform Layer::getTransform() const { } half Layer::getAlpha() const { - auto p = mDrawingParent; + const auto& p = mDrawingParent.promote(); half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf; return parentAlpha * getDrawingState().color.a; @@ -1887,7 +1872,7 @@ ui::Transform::RotationFlags Layer::getFixedTransformHint() const { if (fixedTransformHint != ui::Transform::ROT_INVALID) { return fixedTransformHint; } - auto p = mCurrentParent; + const auto& p = mCurrentParent.promote(); if (!p) return fixedTransformHint; return p->getFixedTransformHint(); } @@ -1898,7 +1883,7 @@ half4 Layer::getColor() const { } int32_t Layer::getBackgroundBlurRadius() const { - auto p = mDrawingParent; + const auto& p = mDrawingParent.promote(); half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf; return parentAlpha * getDrawingState().backgroundBlurRadius; @@ -1916,8 +1901,9 @@ const std::vector Layer::getBlurRegions() const { Layer::RoundedCornerState Layer::getRoundedCornerState() const { // Get parent settings RoundedCornerState parentSettings; - if (mDrawingParent != nullptr) { - parentSettings = mDrawingParent->getRoundedCornerState(); + const auto& parent = mDrawingParent.promote(); + if (parent != nullptr) { + parentSettings = parent->getRoundedCornerState(); if (parentSettings.radius > 0) { ui::Transform t = getActiveTransform(getDrawingState()); t = t.inverse(); @@ -2133,7 +2119,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet LayerProtoHelper::writeToProtoDeprecated(requestedTransform, layerInfo->mutable_requested_transform()); - auto parent = useDrawing ? mDrawingParent : mCurrentParent; + auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote(); if (parent != nullptr) { layerInfo->set_parent(parent->sequence); } else { @@ -2280,9 +2266,9 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTra } void Layer::fillTouchOcclusionMode(WindowInfo& info) { - Layer* p = this; + sp p = this; while (p != nullptr && !p->hasInputInfo()) { - p = p->mDrawingParent; + p = p->mDrawingParent.promote(); } if (p != nullptr) { info.touchOcclusionMode = p->mDrawingState.inputInfo.touchOcclusionMode; @@ -2294,8 +2280,9 @@ gui::DropInputMode Layer::getDropInputMode() const { if (mode == gui::DropInputMode::ALL) { return mode; } - if (mDrawingParent) { - gui::DropInputMode parentMode = mDrawingParent->getDropInputMode(); + sp parent = mDrawingParent.promote(); + if (parent) { + gui::DropInputMode parentMode = parent->getDropInputMode(); if (parentMode != gui::DropInputMode::NONE) { return parentMode; } @@ -2322,7 +2309,8 @@ void Layer::handleDropInputMode(gui::WindowInfo& info) const { } // Check if the parent has set an alpha on the layer - if (mDrawingParent && mDrawingParent->getAlpha() != 1.0_hf) { + sp parent = mDrawingParent.promote(); + if (parent && parent->getAlpha() != 1.0_hf) { info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(), static_cast(getAlpha())); @@ -2420,10 +2408,10 @@ sp Layer::getClonedRoot() { if (mClonedChild != nullptr) { return this; } - if (mDrawingParent == nullptr) { + if (mDrawingParent == nullptr || mDrawingParent.promote() == nullptr) { return nullptr; } - return mDrawingParent->getClonedRoot(); + return mDrawingParent.promote()->getClonedRoot(); } bool Layer::hasInputInfo() const { @@ -2610,7 +2598,8 @@ bool Layer::isInternalDisplayOverlay() const { return true; } - return mDrawingParent && mDrawingParent->isInternalDisplayOverlay(); + sp parent = mDrawingParent.promote(); + return parent && parent->isInternalDisplayOverlay(); } void Layer::setClonedChild(const sp& clonedChild) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 07b2eb5130..8209c51ecb 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -795,12 +795,12 @@ public: // Returns index if removed, or negative value otherwise // for symmetry with Vector::remove ssize_t removeChild(const sp& layer); + sp getParent() const { return mCurrentParent.promote(); } // Should be called with the surfaceflinger statelock held bool isAtRoot() const { return mIsAtRoot; } void setIsAtRoot(bool isAtRoot) { mIsAtRoot = isAtRoot; } - Layer* getParent() const { return mCurrentParent; } bool hasParent() const { return getParent() != nullptr; } Rect getScreenBounds(bool reduceTransparentRegion = true) const; bool setChildLayer(const sp& childLayer, int32_t z); @@ -1007,8 +1007,8 @@ protected: LayerVector mCurrentChildren{LayerVector::StateSet::Current}; LayerVector mDrawingChildren{LayerVector::StateSet::Drawing}; - Layer* mCurrentParent = nullptr; - Layer* mDrawingParent = nullptr; + wp mCurrentParent; + wp mDrawingParent; // Window types from WindowManager.LayoutParams const gui::WindowInfo::Type mWindowType; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index acb81dc41c..81f20edca1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3412,7 +3412,6 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, const spupdateTransformHint(mActiveDisplayTransformHint); - if (outTransformHint) { *outTransformHint = mActiveDisplayTransformHint; } @@ -3957,7 +3956,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( } if (what & layer_state_t::eLayerChanged) { // NOTE: index needs to be calculated before we update the state - auto p = layer->getParent(); + const auto& p = layer->getParent(); if (p == nullptr) { ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); if (layer->setLayer(s.z) && idx >= 0) { @@ -3975,7 +3974,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( } if (what & layer_state_t::eRelativeLayerChanged) { // NOTE: index needs to be calculated before we update the state - auto p = layer->getParent(); + const auto& p = layer->getParent(); const auto& relativeHandle = s.relativeLayerSurfaceControl ? s.relativeLayerSurfaceControl->getHandle() : nullptr; if (p == nullptr) { @@ -6126,7 +6125,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, return; } - auto p = layer; + sp p = layer; while (p != nullptr) { if (excludeLayers.count(p) != 0) { return; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index db3b5722ec..7072439cea 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -289,7 +289,7 @@ public: } static void setLayerDrawingParent(const sp& layer, const sp& drawingParent) { - layer->mDrawingParent = drawingParent.get(); + layer->mDrawingParent = drawingParent; } /* ------------------------------------------------------------------------ -- cgit v1.2.3-59-g8ed1b From 82de19bc5532d68df8f497062882d8d594a4f8f2 Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Thu, 28 Oct 2021 16:34:42 +0200 Subject: Remove dead code around use_frame_rate_api There's no se polixy for ro.surface_flinger.use_frame_rate_api and it cannot be used by vendors, so the code is dead. Removing it cos there isn't a use case for disabling this API. Bug: 199911262 Test: n/a Change-Id: I45aabf5ced73d565a5d7adc73971f3615dde0abe --- services/surfaceflinger/Layer.cpp | 3 --- services/surfaceflinger/SurfaceFlinger.cpp | 3 --- services/surfaceflinger/SurfaceFlinger.h | 5 ----- services/surfaceflinger/SurfaceFlingerProperties.cpp | 8 -------- services/surfaceflinger/SurfaceFlingerProperties.h | 2 -- .../surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop | 10 ---------- .../sysprop/api/SurfaceFlingerProperties-current.txt | 4 ---- .../sysprop/api/SurfaceFlingerProperties-latest.txt | 4 ---- services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp | 2 -- .../surfaceflinger/tests/unittests/TestableSurfaceFlinger.h | 1 - 10 files changed, 42 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 388181c231..94781751fb 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1157,9 +1157,6 @@ void Layer::updateTreeHasFrameRateVote() { } bool Layer::setFrameRate(FrameRate frameRate) { - if (!mFlinger->useFrameRateApi) { - return false; - } if (mDrawingState.frameRate == frameRate) { return false; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8d7221c1dc..0626e7c810 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -339,7 +339,6 @@ Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB; ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888; Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB; ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; -bool SurfaceFlinger::useFrameRateApi; bool SurfaceFlinger::enableSdrDimming; bool SurfaceFlinger::enableLatchUnsignaled; @@ -494,8 +493,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI android::hardware::details::setTrebleTestingOverride(true); } - useFrameRateApi = use_frame_rate_api(true); - mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0); // Debug property overrides ro. property diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 276c7f6bfe..f67c8813a7 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -246,11 +246,6 @@ public: static ui::Dataspace wideColorGamutCompositionDataspace; static ui::PixelFormat wideColorGamutCompositionPixelFormat; - // Whether to use frame rate API when deciding about the refresh rate of the display. This - // variable is caches in SF, so that we can check it with each layer creation, and a void the - // overhead that is caused by reading from sysprop. - static bool useFrameRateApi; - static constexpr SkipInitializationTag SkipInitialization; // Whether or not SDR layers should be dimmed to the desired SDR white point instead of diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index a8117f7f57..16f6e31946 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -304,14 +304,6 @@ bool support_kernel_idle_timer(bool defaultValue) { return defaultValue; } -bool use_frame_rate_api(bool defaultValue) { - auto temp = SurfaceFlingerProperties::use_frame_rate_api(); - if (temp.has_value()) { - return *temp; - } - return defaultValue; -} - bool enable_sdr_dimming(bool defaultValue) { return SurfaceFlingerProperties::enable_sdr_dimming().value_or(defaultValue); } diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index ed182608fb..8d0e4263b1 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -88,8 +88,6 @@ bool enable_protected_contents(bool defaultValue); bool support_kernel_idle_timer(bool defaultValue); -bool use_frame_rate_api(bool defaultValue); - int32_t display_update_imminent_timeout_ms(int32_t defaultValue); android::ui::DisplayPrimaries getDisplayNativePrimaries(); diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index 78f8a2f0ae..7702ea240b 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -414,16 +414,6 @@ prop { prop_name: "ro.surface_flinger.supports_background_blur" } -# Indicates whether Scheduler should use frame rate API when adjusting the -# display refresh rate. -prop { - api_name: "use_frame_rate_api" - type: Boolean - scope: Public - access: Readonly - prop_name: "ro.surface_flinger.use_frame_rate_api" -} - # Sets the timeout used to rate limit DISPLAY_UPDATE_IMMINENT Power HAL notifications. # SurfaceFlinger wakeups will trigger this boost whenever they are separated by more than this # duration (specified in milliseconds). A value of 0 disables the rate limit, and will result in diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt index 9c567d6afa..bf1e7e2908 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -151,10 +151,6 @@ props { api_name: "use_context_priority" prop_name: "ro.surface_flinger.use_context_priority" } - prop { - api_name: "use_frame_rate_api" - prop_name: "ro.surface_flinger.use_frame_rate_api" - } prop { api_name: "use_smart_90_for_video" prop_name: "ro.surface_flinger.use_smart_90_for_video" diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt index ba60a7defb..640b9fb163 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt @@ -135,10 +135,6 @@ props { api_name: "use_context_priority" prop_name: "ro.surface_flinger.use_context_priority" } - prop { - api_name: "use_frame_rate_api" - prop_name: "ro.surface_flinger.use_frame_rate_api" - } prop { api_name: "use_smart_90_for_video" prop_name: "ro.surface_flinger.use_smart_90_for_video" diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 3b409658d7..d0211780ab 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -122,8 +122,6 @@ SetFrameRateTest::SetFrameRateTest() { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - mFlinger.mutableUseFrameRateApi() = true; - setupScheduler(); mFlinger.setupComposer(std::make_unique()); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index c23fcc7d58..2c48779b9d 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -445,7 +445,6 @@ public: auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; } auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; } auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; } - auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; } auto& mutableActiveDisplayToken() { return mFlinger->mActiveDisplayToken; } auto fromHandle(const sp& handle) { -- cgit v1.2.3-59-g8ed1b From da1fd1508c914c7f0849e4e00a5fae5412433337 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 18 Oct 2021 09:36:33 -0700 Subject: SurfaceFlinger: Emit callbacks for non-buffer layer transactions Ensure we emit callbacks if the transaction contains only non-buffer layer state changes. Test: atest SurfaceFlinger_test Fixes: 205183085 Change-Id: I56bf0dcaff4312628fe2cd1d0b93db520518ec54 --- services/surfaceflinger/BufferStateLayer.cpp | 15 ++++++-- services/surfaceflinger/BufferStateLayer.h | 3 +- services/surfaceflinger/Layer.cpp | 11 ++++++ services/surfaceflinger/Layer.h | 6 +-- services/surfaceflinger/SurfaceFlinger.cpp | 21 +++++----- .../surfaceflinger/TransactionCallbackInvoker.cpp | 8 ++-- .../surfaceflinger/TransactionCallbackInvoker.h | 12 +++--- .../surfaceflinger/tests/LayerCallback_test.cpp | 45 +++++++++++++++++++++- 8 files changed, 89 insertions(+), 32 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index c213570c7f..3e09a40eba 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -549,13 +549,19 @@ bool BufferStateLayer::setSidebandStream(const sp& sidebandStream) } bool BufferStateLayer::setTransactionCompletedListeners( - const std::vector>& handles) { + const std::vector& listenerCallbacks, const sp& layerHandle) { // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return - if (handles.empty()) { + if (listenerCallbacks.empty()) { mReleasePreviousBuffer = false; return false; } + std::vector> handles; + handles.reserve(listenerCallbacks.size()); + for (auto& [listener, callbackIds] : listenerCallbacks) { + handles.emplace_back(new CallbackHandle(listener, callbackIds, layerHandle)); + } + const bool willPresent = willPresentCurrentTransaction(); for (const auto& handle : handles) { @@ -571,9 +577,10 @@ bool BufferStateLayer::setTransactionCompletedListeners( // Store so latched time and release fence can be set mDrawingState.callbackHandles.push_back(handle); - } else { // If this layer will NOT need to be relatched and presented this frame + } else { + // If this layer will NOT need to be relatched and presented this frame // Notify the transaction completed thread this handle is done - mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle); + mFlinger->getTransactionCallbackInvoker().addUnpresentedCallbackHandle(handle); } } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index eea700cf7b..ceed188f0e 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -65,7 +65,8 @@ public: bool setSurfaceDamageRegion(const Region& surfaceDamage) override; bool setApi(int32_t api) override; bool setSidebandStream(const sp& sidebandStream) override; - bool setTransactionCompletedListeners(const std::vector>& handles) override; + bool setTransactionCompletedListeners(const std::vector& handles, + const sp& layerHandle) override; bool addFrameEvent(const sp& acquireFence, nsecs_t postedTime, nsecs_t requestedPresentTime) override; bool setPosition(float /*x*/, float /*y*/) override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d68cf9720f..d8854d3033 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2645,6 +2645,17 @@ bool Layer::setDropInputMode(gui::DropInputMode mode) { return true; } +bool Layer::setTransactionCompletedListeners( + const std::vector& listenerCallbacks, const sp&) { + if (listenerCallbacks.empty()) { + return false; + } + for (auto& listener : listenerCallbacks) { + mFlinger->getTransactionCallbackInvoker().addEmptyCallback(listener); + } + return false; +} + // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4569f9af23..f6f162128f 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -426,10 +426,8 @@ public: virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; }; virtual bool setApi(int32_t /*api*/) { return false; }; virtual bool setSidebandStream(const sp& /*sidebandStream*/) { return false; }; - virtual bool setTransactionCompletedListeners( - const std::vector>& /*handles*/) { - return false; - }; + virtual bool setTransactionCompletedListeners(const std::vector& /*handles*/, + const sp& /* layerHandle */); virtual bool addFrameEvent(const sp& /*acquireFence*/, nsecs_t /*postedTime*/, nsecs_t /*requestedPresentTime*/) { return false; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 53a4ae02eb..af6d00041e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3727,11 +3727,10 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin transactionFlags |= setDisplayStateLocked(display); } - // start and end registration for listeners w/ no surface so they can get their callback. Note - // that listeners with SurfaceControls will start registration during setClientStateLocked - // below. + // Add listeners w/ surfaces so they can get their callback. Note that listeners with + // SurfaceControls will start registration during setClientStateLocked below. for (const auto& listener : listenerCallbacks) { - mTransactionCallbackInvoker.addEmptyTransaction(listener); + mTransactionCallbackInvoker.addEmptyCallback(listener); } uint32_t clientStateFlags = 0; @@ -3903,7 +3902,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } if (layer == nullptr) { for (auto& [listener, callbackIds] : s.listeners) { - mTransactionCallbackInvoker.registerUnpresentedCallbackHandle( + mTransactionCallbackInvoker.addUnpresentedCallbackHandle( new CallbackHandle(listener, callbackIds, s.surface)); } return 0; @@ -4173,12 +4172,6 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime flags |= eTransactionNeeded | eTraversalNeeded; } } - std::vector> callbackHandles; - if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) { - for (auto& [listener, callbackIds] : filteredListeners) { - callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface)); - } - } if (what & layer_state_t::eBufferChanged && layer->setBuffer(s.bufferData, postTime, desiredPresentTime, isAutoTimestamp, @@ -4188,7 +4181,11 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime); } - if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; + if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) { + if (layer->setTransactionCompletedListeners(filteredListeners, s.surface)) { + flags |= eTraversalNeeded; + } + } // Do not put anything that updates layer state or modifies flags after // setTransactionCompletedListener return flags; diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index f3d46ea061..418fbc5c44 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -74,10 +74,10 @@ TransactionCallbackInvoker::~TransactionCallbackInvoker() { } } -void TransactionCallbackInvoker::addEmptyTransaction(const ListenerCallbacks& listenerCallbacks) { +void TransactionCallbackInvoker::addEmptyCallback(const ListenerCallbacks& listenerCallbacks) { auto& [listener, callbackIds] = listenerCallbacks; - auto& transactionStatsDeque = mCompletedTransactions[listener]; - transactionStatsDeque.emplace_back(callbackIds); + TransactionStats* transactionStats; + findOrCreateTransactionStats(listener, callbackIds, &transactionStats); } status_t TransactionCallbackInvoker::addOnCommitCallbackHandles( @@ -116,7 +116,7 @@ status_t TransactionCallbackInvoker::addCallbackHandles( return NO_ERROR; } -status_t TransactionCallbackInvoker::registerUnpresentedCallbackHandle( +status_t TransactionCallbackInvoker::addUnpresentedCallbackHandle( const sp& handle) { return addCallbackHandle(handle, std::vector()); } diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index e203d41bd9..6f67947081 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -71,8 +71,10 @@ public: // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and // presented this frame. - status_t registerUnpresentedCallbackHandle(const sp& handle); - void addEmptyTransaction(const ListenerCallbacks& listenerCallbacks); + status_t addUnpresentedCallbackHandle(const sp& handle); + // Adds the callback handles for empty transactions or for non-buffer layer updates which do not + // include layer stats. + void addEmptyCallback(const ListenerCallbacks& listenerCallbacks); void addPresentFence(const sp& presentFence); @@ -81,14 +83,12 @@ public: mCompletedTransactions.clear(); } - status_t addCallbackHandle(const sp& handle, - const std::vector& jankData); - - private: status_t findOrCreateTransactionStats(const sp& listener, const std::vector& callbackIds, TransactionStats** outTransactionStats); + status_t addCallbackHandle(const sp& handle, + const std::vector& jankData); std::unordered_map, std::deque, IListenerHash> mCompletedTransactions; diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 91a5b528f8..7beba15062 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -1067,7 +1067,7 @@ TEST_F(LayerCallbackTest, EmptyBufferStateChanges) { } // b202394221 -TEST_F(LayerCallbackTest, DISABLED_NonBufferLayerStateChanges) { +TEST_F(LayerCallbackTest, NonBufferLayerStateChanges) { sp layer; ASSERT_NO_FATAL_FAILURE(layer = createColorLayer("ColorLayer", Color::RED)); @@ -1085,4 +1085,47 @@ TEST_F(LayerCallbackTest, DISABLED_NonBufferLayerStateChanges) { EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); } +class TimedCallbackHelper { +public: + static void function(void* callbackContext, nsecs_t, const sp&, + const std::vector&) { + if (!callbackContext) { + ALOGE("failed to get callback context"); + } + TimedCallbackHelper* helper = static_cast(callbackContext); + std::lock_guard lock(helper->mMutex); + helper->mInvokedTime = systemTime(); + helper->mCv.notify_all(); + } + + void waitForCallback() { + std::unique_lock lock(mMutex); + ASSERT_TRUE(mCv.wait_for(lock, std::chrono::seconds(3), [&] { return mInvokedTime != -1; })) + << "did not receive callback"; + } + void* getContext() { return static_cast(this); } + + std::mutex mMutex; + std::condition_variable mCv; + nsecs_t mInvokedTime = -1; +}; + +TEST_F(LayerCallbackTest, EmptyTransactionCallbackOrder) { + TimedCallbackHelper onCommitCallback; + TimedCallbackHelper onCompleteCallback; + + // Add transaction callback before on commit callback + Transaction() + .addTransactionCompletedCallback(onCompleteCallback.function, + onCompleteCallback.getContext()) + .addTransactionCommittedCallback(onCommitCallback.function, + onCommitCallback.getContext()) + .apply(); + + EXPECT_NO_FATAL_FAILURE(onCompleteCallback.waitForCallback()); + EXPECT_NO_FATAL_FAILURE(onCommitCallback.waitForCallback()); + // verify we get the oncomplete at the same time or after the oncommit callback. + EXPECT_GE(onCompleteCallback.mInvokedTime, onCommitCallback.mInvokedTime); +} + } // namespace android -- cgit v1.2.3-59-g8ed1b From 7fb9e5a047292114552ba6523bd790269b6cf937 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 8 Nov 2021 12:44:05 -0800 Subject: SF: Create layers with layerid When recreating layer states from transaction traces we need to create layers with a specific layer id. Add the layer id as part of LayerCreationArgs and pass the struct around instead of individual args. Test: presubmit Bug: 200284593 Change-Id: I029cdb5362d1926deaf2ce64f70a1882a418705b --- services/surfaceflinger/BufferQueueLayer.cpp | 2 +- services/surfaceflinger/BufferQueueLayer.h | 5 + services/surfaceflinger/BufferStateLayer.cpp | 2 +- services/surfaceflinger/Client.cpp | 45 +++---- services/surfaceflinger/ContainerLayer.cpp | 3 +- services/surfaceflinger/EffectLayer.cpp | 3 +- services/surfaceflinger/Layer.cpp | 15 +-- services/surfaceflinger/Layer.h | 10 +- services/surfaceflinger/LayerRenderArea.cpp | 4 +- services/surfaceflinger/MonitoredProducer.cpp | 8 +- services/surfaceflinger/SurfaceFlinger.cpp | 132 +++++---------------- services/surfaceflinger/SurfaceFlinger.h | 44 ++----- .../tests/SurfaceInterceptor_test.cpp | 4 +- .../tests/unittests/CompositionTest.cpp | 5 +- .../tests/unittests/FpsReporterTest.cpp | 3 +- .../tests/unittests/GameModeTest.cpp | 2 +- .../tests/unittests/RefreshRateSelectionTest.cpp | 7 +- .../tests/unittests/SetFrameRateTest.cpp | 6 +- .../tests/unittests/TransactionFrameTracerTest.cpp | 2 +- .../unittests/TransactionSurfaceFrameTest.cpp | 2 +- .../unittests/TunnelModeEnabledReporterTest.cpp | 3 +- .../tests/unittests/mock/MockLayer.h | 2 +- 22 files changed, 99 insertions(+), 210 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 28c387e5bd..dec7cc0806 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -523,7 +523,7 @@ void BufferQueueLayer::gatherBufferInfo() { } sp BufferQueueLayer::createClone() { - LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, LayerMetadata()); + LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()); args.textureName = mTextureName; sp layer = mFlinger->getFactory().createBufferQueueLayer(args); layer->setInitialValuesForClone(this); diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index dfdb5c055d..c6e0727806 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -62,6 +62,11 @@ public: status_t setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format); sp getProducer() const; + void setSizeForTest(uint32_t w, uint32_t h) { + mDrawingState.active_legacy.w = w; + mDrawingState.active_legacy.h = h; + } + protected: void gatherBufferInfo() override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index b6cbbb658f..88e3fb6744 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -890,7 +890,7 @@ Rect BufferStateLayer::computeBufferCrop(const State& s) { } sp BufferStateLayer::createClone() { - LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, LayerMetadata()); + LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()); args.textureName = mTextureName; sp layer = mFlinger->getFactory().createBufferStateLayer(args); layer->mHwcSlotGenerator = mHwcSlotGenerator; diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index 8da2e24aa4..0a8ebec9f3 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -72,35 +72,28 @@ sp Client::getLayerUser(const sp& handle) const return lbc; } -status_t Client::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags, const sp& parentHandle, - LayerMetadata metadata, sp* handle, - sp* gbp, int32_t* outLayerId, - uint32_t* outTransformHint) { +status_t Client::createSurface(const String8& name, uint32_t /* w */, uint32_t /* h */, + PixelFormat /* format */, uint32_t flags, + const sp& parentHandle, LayerMetadata metadata, + sp* outHandle, sp* /* gbp */, + int32_t* outLayerId, uint32_t* outTransformHint) { // We rely on createLayer to check permissions. - return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp, - parentHandle, outLayerId, nullptr, outTransformHint); + LayerCreationArgs args(mFlinger.get(), this, name.c_str(), flags, std::move(metadata)); + return mFlinger->createLayer(args, outHandle, parentHandle, outLayerId, nullptr, + outTransformHint); } -status_t Client::createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags, - const sp& parent, - LayerMetadata metadata, sp* handle, - sp* gbp, int32_t* outLayerId, - uint32_t* outTransformHint) { - if (mFlinger->authenticateSurfaceTexture(parent) == false) { - ALOGE("failed to authenticate surface texture"); - return BAD_VALUE; - } - - const auto& layer = (static_cast(parent.get()))->getLayer(); - if (layer == nullptr) { - ALOGE("failed to find parent layer"); - return BAD_VALUE; - } - - return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp, - nullptr, outLayerId, layer, outTransformHint); +status_t Client::createWithSurfaceParent(const String8& /* name */, uint32_t /* w */, + uint32_t /* h */, PixelFormat /* format */, + uint32_t /* flags */, + const sp& /* parent */, + LayerMetadata /* metadata */, sp* /* handle */, + sp* /* gbp */, + int32_t* /* outLayerId */, + uint32_t* /* outTransformHint */) { + // This api does not make sense with blast since SF no longer tracks IGBP. This api should be + // removed. + return BAD_VALUE; } status_t Client::mirrorSurface(const sp& mirrorFromHandle, sp* outHandle, diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp index 841e79f8af..3ccc229261 100644 --- a/services/surfaceflinger/ContainerLayer.cpp +++ b/services/surfaceflinger/ContainerLayer.cpp @@ -36,8 +36,7 @@ bool ContainerLayer::isVisible() const { sp ContainerLayer::createClone() { sp layer = mFlinger->getFactory().createContainerLayer( - LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, - LayerMetadata())); + LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata())); layer->setInitialValuesForClone(this); return layer; } diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp index 86c6b2161c..845176c112 100644 --- a/services/surfaceflinger/EffectLayer.cpp +++ b/services/surfaceflinger/EffectLayer.cpp @@ -136,8 +136,7 @@ ui::Dataspace EffectLayer::getDataSpace() const { sp EffectLayer::createClone() { sp layer = mFlinger->getFactory().createEffectLayer( - LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, - LayerMetadata())); + LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata())); layer->setInitialValuesForClone(this); return layer; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d85e843d83..3d189d681b 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -87,11 +87,12 @@ using gui::WindowInfo; std::atomic Layer::sSequence{1}; Layer::Layer(const LayerCreationArgs& args) - : mFlinger(args.flinger), + : sequence(args.sequence.value_or(sSequence++)), + mFlinger(args.flinger), mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)), mClientRef(args.client), - mWindowType( - static_cast(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))) { + mWindowType(static_cast(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))), + mLayerCreationFlags(args.flags) { uint32_t layerFlags = 0; if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden; if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque; @@ -99,8 +100,6 @@ Layer::Layer(const LayerCreationArgs& args) if (args.flags & ISurfaceComposerClient::eSkipScreenshot) layerFlags |= layer_state_t::eLayerSkipScreenshot; - mDrawingState.active_legacy.w = args.w; - mDrawingState.active_legacy.h = args.h; mDrawingState.flags = layerFlags; mDrawingState.active_legacy.transform.set(0, 0); mDrawingState.crop.makeInvalid(); @@ -185,12 +184,10 @@ Layer::~Layer() { } LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp client, std::string name, - uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata) + uint32_t flags, LayerMetadata metadata) : flinger(flinger), client(std::move(client)), name(std::move(name)), - w(w), - h(h), flags(flags), metadata(std::move(metadata)) { IPCThreadState* ipc = IPCThreadState::self(); @@ -887,7 +884,7 @@ bool Layer::setBackgroundColor(const half3& color, float alpha, ui::Dataspace da uint32_t flags = ISurfaceComposerClient::eFXSurfaceEffect; std::string name = mName + "BackgroundColorLayer"; mDrawingState.bgColorLayer = mFlinger->getFactory().createEffectLayer( - LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), 0, 0, flags, + LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), flags, LayerMetadata())); // add to child list diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index b79903d11b..3da07e824d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -85,20 +85,18 @@ class SurfaceFrame; } // namespace frametimeline struct LayerCreationArgs { - LayerCreationArgs(SurfaceFlinger*, sp, std::string name, uint32_t w, uint32_t h, - uint32_t flags, LayerMetadata); + LayerCreationArgs(SurfaceFlinger*, sp, std::string name, uint32_t flags, LayerMetadata); SurfaceFlinger* flinger; const sp client; std::string name; - uint32_t w; - uint32_t h; uint32_t flags; LayerMetadata metadata; pid_t callingPid; uid_t callingUid; uint32_t textureName; + std::optional sequence = std::nullopt; }; class Layer : public virtual RefBase, compositionengine::LayerFE { @@ -879,7 +877,7 @@ public: // Layer serial number. This gives layers an explicit ordering, so we // have a stable sort order when their layer stack and Z-order are // the same. - int32_t sequence{sSequence++}; + const int32_t sequence; bool mPendingHWCDestroy{false}; @@ -1117,6 +1115,8 @@ private: const std::vector getBlurRegions() const; bool mIsAtRoot = false; + + uint32_t mLayerCreationFlags; }; std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate); diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp index 11fe6d0755..a1e14559e9 100644 --- a/services/surfaceflinger/LayerRenderArea.cpp +++ b/services/surfaceflinger/LayerRenderArea.cpp @@ -112,12 +112,10 @@ void LayerRenderArea::render(std::function drawLayers) { } drawLayers(); } else { - uint32_t w = static_cast(getWidth()); - uint32_t h = static_cast(getHeight()); // In the "childrenOnly" case we reparent the children to a screenshot // layer which has no properties set and which does not draw. sp screenshotParentLayer = mFlinger.getFactory().createContainerLayer( - {&mFlinger, nullptr, "Screenshot Parent"s, w, h, 0, LayerMetadata()}); + {&mFlinger, nullptr, "Screenshot Parent"s, 0, LayerMetadata()}); ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop); drawLayers(); diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index 6b2d745998..df76f50112 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -33,13 +33,7 @@ MonitoredProducer::MonitoredProducer(const sp& producer, mFlinger(flinger), mLayer(layer) {} -MonitoredProducer::~MonitoredProducer() { - // Remove ourselves from SurfaceFlinger's list. We do this asynchronously - // because we don't know where this destructor is called from. It could be - // called with the mStateLock held, leading to a dead-lock (it actually - // happens). - mFlinger->removeGraphicBufferProducerAsync(onAsBinder()); -} +MonitoredProducer::~MonitoredProducer() {} status_t MonitoredProducer::requestBuffer(int slot, sp* buf) { return mProducer->requestBuffer(slot, buf); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c2dcd70166..5a6a8ce05a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -904,9 +904,8 @@ bool SurfaceFlinger::authenticateSurfaceTexture( } bool SurfaceFlinger::authenticateSurfaceTextureLocked( - const sp& bufferProducer) const { - sp surfaceTextureBinder(IInterface::asBinder(bufferProducer)); - return mGraphicBufferProducerList.count(surfaceTextureBinder.get()) > 0; + const sp& /* bufferProducer */) const { + return false; } status_t SurfaceFlinger::getSupportedFrameTimestamps( @@ -3355,20 +3354,15 @@ bool SurfaceFlinger::latchBuffers() { } status_t SurfaceFlinger::addClientLayer(const sp& client, const sp& handle, - const sp& gbc, const sp& lbc, - const wp& parent, bool addToRoot, - uint32_t* outTransformHint) { + const sp& lbc, const wp& parent, + bool addToRoot, uint32_t* outTransformHint) { if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) { ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(), ISurfaceComposer::MAX_LAYERS); return NO_MEMORY; } - wp initialProducer; - if (gbc != nullptr) { - initialProducer = IInterface::asBinder(gbc); - } - setLayerCreatedState(handle, lbc, parent, initialProducer, addToRoot); + setLayerCreatedState(handle, lbc, parent, addToRoot); // Create a transaction includes the initial parent and producer. Vector states; @@ -3384,7 +3378,9 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, const spattachLayer(handle, lbc); + if (client != nullptr) { + client->attachLayer(handle, lbc); + } return setTransactionState(FrameTimelineInfo{}, states, displays, 0 /* flags */, nullptr, InputWindowCommands{}, -1 /* desiredPresentTime */, @@ -3392,13 +3388,6 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, const sp& binder) { - static_cast(schedule([=] { - Mutex::Autolock lock(mStateLock); - mGraphicBufferProducerList.erase(binder); - })); -} - uint32_t SurfaceFlinger::getTransactionFlags() const { return mTransactionFlags; } @@ -4281,17 +4270,14 @@ status_t SurfaceFlinger::mirrorLayer(const sp& client, const sp sp mirrorLayer; sp mirrorFrom; - std::string layerName = "MirrorRoot"; - { Mutex::Autolock _l(mStateLock); mirrorFrom = fromHandle(mirrorFromHandle).promote(); if (!mirrorFrom) { return NAME_NOT_FOUND; } - - status_t result = createContainerLayer(client, std::move(layerName), -1, -1, 0, - LayerMetadata(), outHandle, &mirrorLayer); + LayerCreationArgs args(this, client, "MirrorRoot", 0, LayerMetadata()); + status_t result = createContainerLayer(args, outHandle, &mirrorLayer); if (result != NO_ERROR) { return result; } @@ -4300,22 +4286,13 @@ status_t SurfaceFlinger::mirrorLayer(const sp& client, const sp } *outLayerId = mirrorLayer->sequence; - return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, false, - nullptr /* outTransformHint */); + return addClientLayer(client, *outHandle, mirrorLayer /* layer */, nullptr /* parent */, + false /* addAsRoot */, nullptr /* outTransformHint */); } -status_t SurfaceFlinger::createLayer(const String8& name, const sp& client, uint32_t w, - uint32_t h, PixelFormat format, uint32_t flags, - LayerMetadata metadata, sp* handle, - sp* gbp, +status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp* outHandle, const sp& parentHandle, int32_t* outLayerId, const sp& parentLayer, uint32_t* outTransformHint) { - if (int32_t(w|h) < 0) { - ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)", - int(w), int(h)); - return BAD_VALUE; - } - ALOG_ASSERT(parentLayer == nullptr || parentHandle == nullptr, "Expected only one of parentLayer or parentHandle to be non-null. " "Programmer error?"); @@ -4324,40 +4301,22 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie sp layer; - std::string layerName{name.string()}; - - switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { + switch (args.flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceBufferQueue: case ISurfaceComposerClient::eFXSurfaceBufferState: { - result = createBufferStateLayer(client, std::move(layerName), w, h, flags, - std::move(metadata), handle, &layer); + result = createBufferStateLayer(args, outHandle, &layer); std::atomic* pendingBufferCounter = layer->getPendingBufferCounter(); if (pendingBufferCounter) { std::string counterName = layer->getPendingBufferCounterName(); - mBufferCountTracker.add((*handle)->localBinder(), counterName, + mBufferCountTracker.add((*outHandle)->localBinder(), counterName, pendingBufferCounter); } } break; case ISurfaceComposerClient::eFXSurfaceEffect: - // check if buffer size is set for color layer. - if (w > 0 || h > 0) { - ALOGE("createLayer() failed, w or h cannot be set for color layer (w=%d, h=%d)", - int(w), int(h)); - return BAD_VALUE; - } - - result = createEffectLayer(client, std::move(layerName), w, h, flags, - std::move(metadata), handle, &layer); + result = createEffectLayer(args, outHandle, &layer); break; case ISurfaceComposerClient::eFXSurfaceContainer: - // check if buffer size is set for container layer. - if (w > 0 || h > 0) { - ALOGE("createLayer() failed, w or h cannot be set for container layer (w=%d, h=%d)", - int(w), int(h)); - return BAD_VALUE; - } - result = createContainerLayer(client, std::move(layerName), w, h, flags, - std::move(metadata), handle, &layer); + result = createContainerLayer(args, outHandle, &layer); break; default: result = BAD_VALUE; @@ -4377,7 +4336,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie if (parentLayer != nullptr) { addToRoot = false; } - result = addClientLayer(client, *handle, *gbp, layer, parent, addToRoot, outTransformHint); + result = addClientLayer(args.client, *outHandle, layer, parent, addToRoot, outTransformHint); if (result != NO_ERROR) { return result; } @@ -4387,9 +4346,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie return result; } -status_t SurfaceFlinger::createBufferQueueLayer(const sp& client, std::string name, - uint32_t w, uint32_t h, uint32_t flags, - LayerMetadata metadata, PixelFormat& format, +status_t SurfaceFlinger::createBufferQueueLayer(LayerCreationArgs& args, PixelFormat& format, sp* handle, sp* gbp, sp* outLayer) { @@ -4405,7 +4362,6 @@ status_t SurfaceFlinger::createBufferQueueLayer(const sp& client, std::s } sp layer; - LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata)); args.textureName = getNewTexture(); { // Grab the SF state lock during this since it's the only safe way to access @@ -4415,7 +4371,7 @@ status_t SurfaceFlinger::createBufferQueueLayer(const sp& client, std::s layer = getFactory().createBufferQueueLayer(args); } - status_t err = layer->setDefaultBufferProperties(w, h, format); + status_t err = layer->setDefaultBufferProperties(0, 0, format); if (err == NO_ERROR) { *handle = layer->getHandle(); *gbp = layer->getProducer(); @@ -4426,34 +4382,24 @@ status_t SurfaceFlinger::createBufferQueueLayer(const sp& client, std::s return err; } -status_t SurfaceFlinger::createBufferStateLayer(const sp& client, std::string name, - uint32_t w, uint32_t h, uint32_t flags, - LayerMetadata metadata, sp* handle, +status_t SurfaceFlinger::createBufferStateLayer(LayerCreationArgs& args, sp* handle, sp* outLayer) { - LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata)); args.textureName = getNewTexture(); - sp layer = getFactory().createBufferStateLayer(args); - *handle = layer->getHandle(); - *outLayer = layer; - + *outLayer = getFactory().createBufferStateLayer(args); + *handle = (*outLayer)->getHandle(); return NO_ERROR; } -status_t SurfaceFlinger::createEffectLayer(const sp& client, std::string name, uint32_t w, - uint32_t h, uint32_t flags, LayerMetadata metadata, - sp* handle, sp* outLayer) { - *outLayer = getFactory().createEffectLayer( - {this, client, std::move(name), w, h, flags, std::move(metadata)}); +status_t SurfaceFlinger::createEffectLayer(LayerCreationArgs& args, sp* handle, + sp* outLayer) { + *outLayer = getFactory().createEffectLayer(args); *handle = (*outLayer)->getHandle(); return NO_ERROR; } -status_t SurfaceFlinger::createContainerLayer(const sp& client, std::string name, - uint32_t w, uint32_t h, uint32_t flags, - LayerMetadata metadata, sp* handle, +status_t SurfaceFlinger::createContainerLayer(LayerCreationArgs& args, sp* handle, sp* outLayer) { - *outLayer = getFactory().createContainerLayer( - {this, client, std::move(name), w, h, flags, std::move(metadata)}); + *outLayer = getFactory().createContainerLayer(args); *handle = (*outLayer)->getHandle(); return NO_ERROR; } @@ -5039,8 +4985,6 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co */ colorizer.bold(result); StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers.load()); - StringAppendF(&result, "GraphicBufferProducers: %zu, max %zu\n", - mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize); colorizer.reset(result); { @@ -6802,11 +6746,10 @@ void TransactionState::traverseStatesWithBuffers( } void SurfaceFlinger::setLayerCreatedState(const sp& handle, const wp& layer, - const wp parent, const wp& producer, - bool addToRoot) { + const wp parent, bool addToRoot) { Mutex::Autolock lock(mCreatedLayersLock); mCreatedLayers[handle->localBinder()] = - std::make_unique(layer, parent, producer, addToRoot); + std::make_unique(layer, parent, addToRoot); } auto SurfaceFlinger::getLayerCreatedState(const sp& handle) { @@ -6867,19 +6810,6 @@ sp SurfaceFlinger::handleLayerCreatedLocked(const sp& handle) { layer->updateTransformHint(mActiveDisplayTransformHint); - if (state->initialProducer != nullptr) { - mGraphicBufferProducerList.insert(state->initialProducer); - LOG_ALWAYS_FATAL_IF(mGraphicBufferProducerList.size() > mMaxGraphicBufferProducerListSize, - "Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers", - mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize, - mNumLayers.load()); - if (mGraphicBufferProducerList.size() > mGraphicBufferProducerListSizeLogThreshold) { - ALOGW("Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers", - mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize, - mNumLayers.load()); - } - } - mInterceptor->saveSurfaceCreation(layer); return layer; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index bf628dc309..b432f246c0 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -763,29 +763,23 @@ private: /* * Layer management */ - status_t createLayer(const String8& name, const sp& client, uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags, LayerMetadata metadata, - sp* handle, sp* gbp, + status_t createLayer(LayerCreationArgs& args, sp* outHandle, const sp& parentHandle, int32_t* outLayerId, const sp& parentLayer = nullptr, uint32_t* outTransformHint = nullptr); - status_t createBufferQueueLayer(const sp& client, std::string name, uint32_t w, - uint32_t h, uint32_t flags, LayerMetadata metadata, - PixelFormat& format, sp* outHandle, - sp* outGbp, sp* outLayer); + status_t createBufferQueueLayer(LayerCreationArgs& args, PixelFormat& format, + sp* outHandle, sp* outGbp, + sp* outLayer); - status_t createBufferStateLayer(const sp& client, std::string name, uint32_t w, - uint32_t h, uint32_t flags, LayerMetadata metadata, - sp* outHandle, sp* outLayer); + status_t createBufferStateLayer(LayerCreationArgs& args, sp* outHandle, + sp* outLayer); - status_t createEffectLayer(const sp& client, std::string name, uint32_t w, uint32_t h, - uint32_t flags, LayerMetadata metadata, sp* outHandle, + status_t createEffectLayer(LayerCreationArgs& args, sp* outHandle, sp* outLayer); - status_t createContainerLayer(const sp& client, std::string name, uint32_t w, - uint32_t h, uint32_t flags, LayerMetadata metadata, - sp* outHandle, sp* outLayer); + status_t createContainerLayer(LayerCreationArgs& args, sp* outHandle, + sp* outLayer); status_t mirrorLayer(const sp& client, const sp& mirrorFromHandle, sp* outHandle, int32_t* outLayerId); @@ -798,8 +792,7 @@ private: // add a layer to SurfaceFlinger status_t addClientLayer(const sp& client, const sp& handle, - const sp& gbc, const sp& lbc, - const wp& parentLayer, bool addToRoot, + const sp& lbc, const wp& parentLayer, bool addToRoot, uint32_t* outTransformHint); // Traverse through all the layers and compute and cache its bounds. @@ -1115,16 +1108,12 @@ private: float mGlobalSaturationFactor = 1.0f; mat4 mClientColorMatrix; - // Can't be unordered_set because wp<> isn't hashable - std::set> mGraphicBufferProducerList; size_t mMaxGraphicBufferProducerListSize = ISurfaceComposer::MAX_LAYERS; // If there are more GraphicBufferProducers tracked by SurfaceFlinger than // this threshold, then begin logging. size_t mGraphicBufferProducerListSizeLogThreshold = static_cast(0.95 * static_cast(MAX_LAYERS)); - void removeGraphicBufferProducerAsync(const wp&); - // protected by mStateLock (but we could use another lock) bool mLayersRemoved = false; bool mLayersAdded = false; @@ -1339,19 +1328,12 @@ private: GUARDED_BY(mStateLock); mutable Mutex mCreatedLayersLock; struct LayerCreatedState { - LayerCreatedState(const wp& layer, const wp parent, - const wp& producer, bool addToRoot) - : layer(layer), - initialParent(parent), - initialProducer(producer), - addToRoot(addToRoot) {} + LayerCreatedState(const wp& layer, const wp parent, bool addToRoot) + : layer(layer), initialParent(parent), addToRoot(addToRoot) {} wp layer; // Indicates the initial parent of the created layer, only used for creating layer in // SurfaceFlinger. If nullptr, it may add the created layer into the current root layers. wp initialParent; - // Indicates the initial graphic buffer producer of the created layer, only used for - // creating layer in SurfaceFlinger. - wp initialProducer; // Indicates whether the layer getting created should be added at root if there's no parent // and has permission ACCESS_SURFACE_FLINGER. If set to false and no parent, the layer will // be added offscreen. @@ -1362,7 +1344,7 @@ private: // thread. std::unordered_map> mCreatedLayers; void setLayerCreatedState(const sp& handle, const wp& layer, - const wp parent, const wp& producer, bool addToRoot); + const wp parent, bool addToRoot); auto getLayerCreatedState(const sp& handle); sp handleLayerCreatedLocked(const sp& handle) REQUIRES(mStateLock); diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 2082c42001..28e8b8c78b 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -754,9 +754,7 @@ void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) { } bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) { - bool isMatch(increment.surface_creation().name() == getUniqueName(LAYER_NAME, increment) && - increment.surface_creation().w() == SIZE_UPDATE && - increment.surface_creation().h() == SIZE_UPDATE); + bool isMatch(increment.surface_creation().name() == getUniqueName(LAYER_NAME, increment)); if (isMatch && !foundSurface) { foundSurface = true; } else if (isMatch && foundSurface) { diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 40ef6e702d..52d8c35ede 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -535,6 +535,7 @@ struct BaseLayerProperties { static void setupLatchedBuffer(CompositionTest* test, sp layer) { // TODO: Eliminate the complexity of actually creating a buffer + layer->setSizeForTest(LayerProperties::WIDTH, LayerProperties::HEIGHT); status_t err = layer->setDefaultBufferProperties(LayerProperties::WIDTH, LayerProperties::HEIGHT, LayerProperties::FORMAT); @@ -901,7 +902,6 @@ struct EffectLayerVariant : public BaseLayerVariant { FlingerLayerType layer = Base::template createLayerWithFactory(test, [test]() { return new EffectLayer( LayerCreationArgs(test->mFlinger.flinger(), sp(), "test-layer", - LayerProperties::WIDTH, LayerProperties::HEIGHT, LayerProperties::LAYER_FLAGS, LayerMetadata())); }); @@ -940,7 +940,6 @@ struct BufferLayerVariant : public BaseLayerVariant { FlingerLayerType layer = Base::template createLayerWithFactory(test, [test]() { LayerCreationArgs args(test->mFlinger.flinger(), sp(), "test-layer", - LayerProperties::WIDTH, LayerProperties::HEIGHT, LayerProperties::LAYER_FLAGS, LayerMetadata()); args.textureName = test->mFlinger.mutableTexturePool().back(); return new BufferQueueLayer(args); @@ -952,7 +951,6 @@ struct BufferLayerVariant : public BaseLayerVariant { } static void cleanupInjectedLayers(CompositionTest* test) { - EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(1); Base::cleanupInjectedLayers(test); } @@ -990,7 +988,6 @@ struct ContainerLayerVariant : public BaseLayerVariant { static FlingerLayerType createLayer(CompositionTest* test) { LayerCreationArgs args(test->mFlinger.flinger(), sp(), "test-container-layer", - LayerProperties::WIDTH, LayerProperties::HEIGHT, LayerProperties::LAYER_FLAGS, LayerMetadata()); FlingerLayerType layer = new ContainerLayer(args); Base::template initLayerDrawingStateAndComputeBounds(test, layer); diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp index 010c675574..cd2fc7426e 100644 --- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp @@ -114,8 +114,7 @@ FpsReporterTest::~FpsReporterTest() { sp FpsReporterTest::createBufferStateLayer(LayerMetadata metadata = {}) { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", WIDTH, HEIGHT, - LAYER_FLAGS, metadata); + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, metadata); return new BufferStateLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/GameModeTest.cpp b/services/surfaceflinger/tests/unittests/GameModeTest.cpp index 3fa1a2c2f5..d6459429fb 100644 --- a/services/surfaceflinger/tests/unittests/GameModeTest.cpp +++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp @@ -53,7 +53,7 @@ public: sp createBufferStateLayer() { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0, + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0, LayerMetadata()); return new BufferStateLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp index e388a6f40f..1e6e3361b2 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp @@ -91,15 +91,14 @@ RefreshRateSelectionTest::~RefreshRateSelectionTest() { sp RefreshRateSelectionTest::createBufferStateLayer() { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT, - LAYER_FLAGS, LayerMetadata()); + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", LAYER_FLAGS, + LayerMetadata()); return new BufferStateLayer(args); } sp RefreshRateSelectionTest::createEffectLayer() { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS, - LayerMetadata()); + LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata()); return new EffectLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index d0211780ab..360f9c684f 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -70,8 +70,8 @@ public: std::string name() override { return "BufferStateLayer"; } sp createLayer(TestableSurfaceFlinger& flinger) override { sp client; - LayerCreationArgs args(flinger.flinger(), client, "buffer-state-layer", WIDTH, HEIGHT, - LAYER_FLAGS, LayerMetadata()); + LayerCreationArgs args(flinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, + LayerMetadata()); return new BufferStateLayer(args); } }; @@ -81,7 +81,7 @@ public: std::string name() override { return "EffectLayer"; } sp createLayer(TestableSurfaceFlinger& flinger) override { sp client; - LayerCreationArgs args(flinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS, + LayerCreationArgs args(flinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata()); return new EffectLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index bd6a7805ec..deeb785bb9 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -57,7 +57,7 @@ public: sp createBufferStateLayer() { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0, + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0, LayerMetadata()); return new BufferStateLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index bf69704210..704340deac 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -57,7 +57,7 @@ public: sp createBufferStateLayer() { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0, + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0, LayerMetadata()); return new BufferStateLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp index e4f74694f7..ade4fbb850 100644 --- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp @@ -100,8 +100,7 @@ TunnelModeEnabledReporterTest::~TunnelModeEnabledReporterTest() { sp TunnelModeEnabledReporterTest::createBufferStateLayer( LayerMetadata metadata = {}) { sp client; - LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", WIDTH, HEIGHT, - LAYER_FLAGS, metadata); + LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, metadata); return new BufferStateLayer(args); } diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h index ba2e4db0fa..8b48e1c16d 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -25,7 +25,7 @@ namespace android::mock { class MockLayer : public Layer { public: MockLayer(SurfaceFlinger* flinger, std::string name) - : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 800, 600, 0, {})) {} + : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {} explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {} MOCK_CONST_METHOD0(getType, const char*()); -- cgit v1.2.3-59-g8ed1b From 00b9013d323caceec2528326809bf65d50c39c72 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 5 Nov 2021 14:03:40 -0700 Subject: SF: Simplify layer tracing As preparation to support transaction tracing, do the following: 1. refactor the ring buffer code so it can be reused 2. remove layer async tracing since we will use transaction tracing for always on tracing Test: presubmit Test: capture sf trace via bugreport Bug: 200284593 Change-Id: I28388c6db27a420c078e1cc33b0b378c55c6c5d6 --- services/surfaceflinger/Android.bp | 2 +- services/surfaceflinger/Layer.cpp | 163 +++++++------- services/surfaceflinger/Layer.h | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 44 ++-- services/surfaceflinger/SurfaceFlinger.h | 11 +- services/surfaceflinger/SurfaceTracing.cpp | 264 ----------------------- services/surfaceflinger/SurfaceTracing.h | 164 -------------- services/surfaceflinger/Tracing/LayerTracing.cpp | 130 +++++++++++ services/surfaceflinger/Tracing/LayerTracing.h | 77 +++++++ services/surfaceflinger/Tracing/RingBuffer.h | 112 ++++++++++ 10 files changed, 420 insertions(+), 551 deletions(-) delete mode 100644 services/surfaceflinger/SurfaceTracing.cpp delete mode 100644 services/surfaceflinger/SurfaceTracing.h create mode 100644 services/surfaceflinger/Tracing/LayerTracing.cpp create mode 100644 services/surfaceflinger/Tracing/LayerTracing.h create mode 100644 services/surfaceflinger/Tracing/RingBuffer.h (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 56b8374eb0..4e29172609 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -200,7 +200,7 @@ filegroup { "SurfaceFlinger.cpp", "SurfaceFlingerDefaultFactory.cpp", "SurfaceInterceptor.cpp", - "SurfaceTracing.cpp", + "Tracing/LayerTracing.cpp", "Tracing/TransactionProtoParser.cpp", "TransactionCallbackInvoker.cpp", "TunnelModeEnabledReporter.cpp", diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3d189d681b..f5c5b4a70a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2005,7 +2005,7 @@ LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags, writeToProtoDrawingState(layerProto, traceFlags, display); writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags); - if (traceFlags & SurfaceTracing::TRACE_COMPOSITION) { + if (traceFlags & LayerTracing::TRACE_COMPOSITION) { // Only populate for the primary display. if (display) { const Hwc2::IComposerClient::Composition compositionType = getCompositionType(*display); @@ -2023,43 +2023,38 @@ LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags, void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, const DisplayDevice* display) { const ui::Transform transform = getTransform(); + auto buffer = getBuffer(); + if (buffer != nullptr) { + LayerProtoHelper::writeToProto(buffer, + [&]() { return layerInfo->mutable_active_buffer(); }); + LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()), + layerInfo->mutable_buffer_transform()); + } + layerInfo->set_invalidate(contentDirty); + layerInfo->set_is_protected(isProtected()); + layerInfo->set_dataspace(dataspaceDetails(static_cast(getDataSpace()))); + layerInfo->set_queued_frames(getQueuedFrameCount()); + layerInfo->set_refresh_pending(isBufferLatched()); + layerInfo->set_curr_frame(mCurrentFrameNumber); + layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); + + layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius); + layerInfo->set_corner_radius(getRoundedCornerState().radius); + layerInfo->set_background_blur_radius(getBackgroundBlurRadius()); + layerInfo->set_is_trusted_overlay(isTrustedOverlay()); + LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform()); + LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), + [&]() { return layerInfo->mutable_position(); }); + LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); + if (traceFlags & LayerTracing::TRACE_COMPOSITION) { + LayerProtoHelper::writeToProto(getVisibleRegion(display), + [&]() { return layerInfo->mutable_visible_region(); }); + } + LayerProtoHelper::writeToProto(surfaceDamageRegion, + [&]() { return layerInfo->mutable_damage_region(); }); - if (traceFlags & SurfaceTracing::TRACE_CRITICAL) { - - auto buffer = getBuffer(); - if (buffer != nullptr) { - LayerProtoHelper::writeToProto(buffer, - [&]() { return layerInfo->mutable_active_buffer(); }); - LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()), - layerInfo->mutable_buffer_transform()); - } - layerInfo->set_invalidate(contentDirty); - layerInfo->set_is_protected(isProtected()); - layerInfo->set_dataspace(dataspaceDetails(static_cast(getDataSpace()))); - layerInfo->set_queued_frames(getQueuedFrameCount()); - layerInfo->set_refresh_pending(isBufferLatched()); - layerInfo->set_curr_frame(mCurrentFrameNumber); - layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); - - layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius); - layerInfo->set_corner_radius(getRoundedCornerState().radius); - layerInfo->set_background_blur_radius(getBackgroundBlurRadius()); - layerInfo->set_is_trusted_overlay(isTrustedOverlay()); - LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform()); - LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), - [&]() { return layerInfo->mutable_position(); }); - LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); - if (traceFlags & SurfaceTracing::TRACE_COMPOSITION) { - LayerProtoHelper::writeToProto(getVisibleRegion(display), - [&]() { return layerInfo->mutable_visible_region(); }); - } - LayerProtoHelper::writeToProto(surfaceDamageRegion, - [&]() { return layerInfo->mutable_damage_region(); }); - - if (hasColorTransform()) { - LayerProtoHelper::writeToProto(getColorTransform(), - layerInfo->mutable_color_transform()); - } + if (hasColorTransform()) { + LayerProtoHelper::writeToProto(getColorTransform(), layerInfo->mutable_color_transform()); } LayerProtoHelper::writeToProto(mSourceBounds, @@ -2079,70 +2074,66 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet ui::Transform requestedTransform = state.transform; - if (traceFlags & SurfaceTracing::TRACE_CRITICAL) { - layerInfo->set_id(sequence); - layerInfo->set_name(getName().c_str()); - layerInfo->set_type(getType()); + layerInfo->set_id(sequence); + layerInfo->set_name(getName().c_str()); + layerInfo->set_type(getType()); - for (const auto& child : children) { - layerInfo->add_children(child->sequence); - } + for (const auto& child : children) { + layerInfo->add_children(child->sequence); + } - for (const wp& weakRelative : state.zOrderRelatives) { - sp strongRelative = weakRelative.promote(); - if (strongRelative != nullptr) { - layerInfo->add_relatives(strongRelative->sequence); - } + for (const wp& weakRelative : state.zOrderRelatives) { + sp strongRelative = weakRelative.promote(); + if (strongRelative != nullptr) { + layerInfo->add_relatives(strongRelative->sequence); } + } - LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy, - [&]() { return layerInfo->mutable_transparent_region(); }); - - layerInfo->set_layer_stack(getLayerStack().id); - layerInfo->set_z(state.z); + LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy, + [&]() { return layerInfo->mutable_transparent_region(); }); - LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), - [&]() { - return layerInfo->mutable_requested_position(); - }); + layerInfo->set_layer_stack(getLayerStack().id); + layerInfo->set_z(state.z); - LayerProtoHelper::writeSizeToProto(state.width, state.height, - [&]() { return layerInfo->mutable_size(); }); + LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() { + return layerInfo->mutable_requested_position(); + }); - LayerProtoHelper::writeToProto(state.crop, [&]() { return layerInfo->mutable_crop(); }); + LayerProtoHelper::writeSizeToProto(state.width, state.height, + [&]() { return layerInfo->mutable_size(); }); - layerInfo->set_is_opaque(isOpaque(state)); + LayerProtoHelper::writeToProto(state.crop, [&]() { return layerInfo->mutable_crop(); }); + layerInfo->set_is_opaque(isOpaque(state)); - layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat())); - LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); }); - LayerProtoHelper::writeToProto(state.color, - [&]() { return layerInfo->mutable_requested_color(); }); - layerInfo->set_flags(state.flags); + layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat())); + LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); }); + LayerProtoHelper::writeToProto(state.color, + [&]() { return layerInfo->mutable_requested_color(); }); + layerInfo->set_flags(state.flags); - LayerProtoHelper::writeToProtoDeprecated(requestedTransform, - layerInfo->mutable_requested_transform()); + LayerProtoHelper::writeToProtoDeprecated(requestedTransform, + layerInfo->mutable_requested_transform()); - auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote(); - if (parent != nullptr) { - layerInfo->set_parent(parent->sequence); - } else { - layerInfo->set_parent(-1); - } + auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote(); + if (parent != nullptr) { + layerInfo->set_parent(parent->sequence); + } else { + layerInfo->set_parent(-1); + } - auto zOrderRelativeOf = state.zOrderRelativeOf.promote(); - if (zOrderRelativeOf != nullptr) { - layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence); - } else { - layerInfo->set_z_order_relative_of(-1); - } + auto zOrderRelativeOf = state.zOrderRelativeOf.promote(); + if (zOrderRelativeOf != nullptr) { + layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence); + } else { + layerInfo->set_z_order_relative_of(-1); + } - layerInfo->set_is_relative_of(state.isRelativeOf); + layerInfo->set_is_relative_of(state.isRelativeOf); - layerInfo->set_owner_uid(mOwnerUid); - } + layerInfo->set_owner_uid(mOwnerUid); - if (traceFlags & SurfaceTracing::TRACE_INPUT) { + if (traceFlags & LayerTracing::TRACE_INPUT) { WindowInfo info; if (useDrawing) { info = fillInputInfo(ui::Transform(), /* displayIsSecure */ true); @@ -2154,7 +2145,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet [&]() { return layerInfo->mutable_input_window_info(); }); } - if (traceFlags & SurfaceTracing::TRACE_EXTRA) { + if (traceFlags & LayerTracing::TRACE_EXTRA) { auto protoMap = layerInfo->mutable_metadata(); for (const auto& entry : state.metadata.mMap) { (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend()); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 3da07e824d..5af8dda2fc 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -57,7 +57,7 @@ #include "Scheduler/LayerInfo.h" #include "Scheduler/Seamlessness.h" #include "SurfaceFlinger.h" -#include "SurfaceTracing.h" +#include "Tracing/LayerTracing.h" #include "TransactionCallbackInvoker.h" using namespace android::surfaceflinger; @@ -691,7 +691,7 @@ public: // external mStateLock. If writing drawing state, this function should be called on the // main or tracing thread. void writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet, - uint32_t traceFlags = SurfaceTracing::TRACE_ALL); + uint32_t traceFlags = LayerTracing::TRACE_ALL); gui::WindowInfo::Type getWindowType() const { return mWindowType; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5a6a8ce05a..a990e6b893 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1948,7 +1948,7 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected } if (mTracingEnabledChanged) { - mTracingEnabled = mTracing.isEnabled(); + mTracingEnabled = mLayerTracing.isEnabled(); mTracingEnabledChanged = false; } @@ -1962,24 +1962,12 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected // Composite if transactions were committed, or if requested by HWC. bool mustComposite = mMustComposite.exchange(false); { - mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) || - mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) || - mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS); - const bool tracePreComposition = mTracingEnabled && !mTracePostComposition; - ConditionalLockGuard lock(mTracingLock, tracePreComposition); - mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(stats.vsyncPeriod)); mustComposite |= flushAndCommitTransactions(); mustComposite |= latchBuffers(); updateLayerGeometry(); - - if (tracePreComposition) { - if (mVisibleRegionsDirty) { - mTracing.notifyLocked("visibleRegionsDirty"); - } - } } // Layers need to get updated (in the previous line) before we can use them for @@ -2112,12 +2100,12 @@ void SurfaceFlinger::composite(nsecs_t frameTime) { modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition); mLayersWithQueuedFrames.clear(); - if (mTracingEnabled && mTracePostComposition) { - // This may block if SurfaceTracing is running in sync mode. + if (mTracingEnabled) { + // This will block and should only be used for debugging. if (mVisibleRegionsDirty) { - mTracing.notify("visibleRegionsDirty"); - } else if (mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS)) { - mTracing.notify("bufferLatched"); + mLayerTracing.notify("visibleRegionsDirty"); + } else if (mLayerTracing.flagIsSet(LayerTracing::TRACE_BUFFERS)) { + mLayerTracing.notify("bufferLatched"); } } @@ -4647,7 +4635,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { } if (dumpLayers) { - LayersTraceFileProto traceFileProto = SurfaceTracing::createLayersTraceFileProto(); + LayersTraceFileProto traceFileProto = mLayerTracing.createTraceFileProto(); LayersTraceProto* layersTrace = traceFileProto.add_entry(); LayersProto layersProto = dumpProtoFromMainThread(); layersTrace->mutable_layers()->Swap(&layersProto); @@ -4669,8 +4657,8 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { } status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) { - if (asProto && mTracing.isEnabled()) { - mTracing.writeToFile(); + if (asProto && mLayerTracing.isEnabled()) { + mLayerTracing.writeToFile(); } return doDump(fd, DumpArgs(), asProto); @@ -5066,7 +5054,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co /* * Tracing state */ - mTracing.dump(result); + mLayerTracing.dump(result); result.append("\n"); /* @@ -5493,20 +5481,20 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r bool tracingEnabledChanged; if (n) { ALOGD("LayerTracing enabled"); - tracingEnabledChanged = mTracing.enable(); + tracingEnabledChanged = mLayerTracing.enable(); if (tracingEnabledChanged) { - schedule([&]() MAIN_THREAD { mTracing.notify("start"); }).wait(); + schedule([&]() MAIN_THREAD { mLayerTracing.notify("start"); }).wait(); } } else { ALOGD("LayerTracing disabled"); - tracingEnabledChanged = mTracing.disable(); + tracingEnabledChanged = mLayerTracing.disable(); } mTracingEnabledChanged = tracingEnabledChanged; reply->writeInt32(NO_ERROR); return NO_ERROR; } case 1026: { // Get layer tracing status - reply->writeBool(mTracing.isEnabled()); + reply->writeBool(mLayerTracing.isEnabled()); return NO_ERROR; } // Is a DisplayColorSetting supported? @@ -5547,7 +5535,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } ALOGD("Updating trace buffer to %d KB", n); - mTracing.setBufferSize(n * 1024); + mLayerTracing.setBufferSize(n * 1024); reply->writeInt32(NO_ERROR); return NO_ERROR; } @@ -5592,7 +5580,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r case 1033: { n = data.readUint32(); ALOGD("Updating trace flags to 0x%x", n); - mTracing.setTraceFlags(n); + mLayerTracing.setTraceFlags(n); reply->writeInt32(NO_ERROR); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b432f246c0..e3bcde2070 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -62,8 +62,8 @@ #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncModulator.h" #include "SurfaceFlingerFactory.h" -#include "SurfaceTracing.h" #include "TracedOrdinal.h" +#include "Tracing/LayerTracing.h" #include "TransactionCallbackInvoker.h" #include "TransactionState.h" @@ -353,7 +353,7 @@ private: friend class MonitoredProducer; friend class RefreshRateOverlay; friend class RegionSamplingThread; - friend class SurfaceTracing; + friend class LayerTracing; // For unit tests friend class TestableSurfaceFlinger; @@ -1042,12 +1042,12 @@ private: void dumpWideColorInfo(std::string& result) const REQUIRES(mStateLock); LayersProto dumpDrawingStateProto(uint32_t traceFlags) const; void dumpOffscreenLayersProto(LayersProto& layersProto, - uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const; + uint32_t traceFlags = LayerTracing::TRACE_ALL) const; void dumpDisplayProto(LayersTraceProto& layersTraceProto) const; // Dumps state from HW Composer void dumpHwc(std::string& result) const; - LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) + LayersProto dumpProtoFromMainThread(uint32_t traceFlags = LayerTracing::TRACE_ALL) EXCLUDES(mStateLock); void dumpOffscreenLayers(std::string& result) EXCLUDES(mStateLock); void dumpPlannerInfo(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock); @@ -1190,10 +1190,9 @@ private: bool mPropagateBackpressureClientComposition = false; sp mInterceptor; - SurfaceTracing mTracing{*this}; + LayerTracing mLayerTracing{*this}; std::mutex mTracingLock; bool mTracingEnabled = false; - bool mTracePostComposition = false; std::atomic mTracingEnabledChanged = false; const std::shared_ptr mTimeStats; diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp deleted file mode 100644 index 596373732f..0000000000 --- a/services/surfaceflinger/SurfaceTracing.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#undef LOG_TAG -#define LOG_TAG "SurfaceTracing" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "SurfaceTracing.h" -#include - -#include -#include -#include -#include -#include - -namespace android { - -SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {} - -bool SurfaceTracing::enable() { - std::scoped_lock lock(mTraceLock); - if (mEnabled) { - return false; - } - - if (flagIsSet(TRACE_SYNC)) { - runner = std::make_unique(mFlinger, mConfig); - } else { - runner = std::make_unique(mFlinger, mConfig, - mFlinger.mTracingLock); - } - mEnabled = true; - return true; -} - -bool SurfaceTracing::disable() { - std::scoped_lock lock(mTraceLock); - if (!mEnabled) { - return false; - } - mEnabled = false; - runner->stop(); - return true; -} - -bool SurfaceTracing::isEnabled() const { - std::scoped_lock lock(mTraceLock); - return mEnabled; -} - -status_t SurfaceTracing::writeToFile() { - std::scoped_lock lock(mTraceLock); - if (!mEnabled) { - return STATUS_OK; - } - return runner->writeToFile(); -} - -void SurfaceTracing::notify(const char* where) { - std::scoped_lock lock(mTraceLock); - if (mEnabled) { - runner->notify(where); - } -} - -void SurfaceTracing::notifyLocked(const char* where) { - std::scoped_lock lock(mTraceLock); - if (mEnabled) { - runner->notifyLocked(where); - } -} - -void SurfaceTracing::dump(std::string& result) const { - std::scoped_lock lock(mTraceLock); - base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled"); - if (mEnabled) { - runner->dump(result); - } -} - -void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) { - // use the swap trick to make sure memory is released - std::queue().swap(mStorage); - mSizeInBytes = newSize; - mUsedInBytes = 0U; -} - -void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) { - size_t protoSize = static_cast(proto.ByteSize()); - while (mUsedInBytes + protoSize > mSizeInBytes) { - if (mStorage.empty()) { - return; - } - mUsedInBytes -= static_cast(mStorage.front().ByteSize()); - mStorage.pop(); - } - mUsedInBytes += protoSize; - mStorage.emplace(); - mStorage.back().Swap(&proto); -} - -void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) { - fileProto->mutable_entry()->Reserve(static_cast(mStorage.size())); - - while (!mStorage.empty()) { - auto entry = fileProto->add_entry(); - entry->Swap(&mStorage.front()); - mStorage.pop(); - } -} - -SurfaceTracing::Runner::Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config) - : mFlinger(flinger), mConfig(config) { - mBuffer.setSize(mConfig.bufferSize); -} - -void SurfaceTracing::Runner::notify(const char* where) { - LayersTraceProto entry = traceLayers(where); - mBuffer.emplace(std::move(entry)); -} - -status_t SurfaceTracing::Runner::stop() { - return writeToFile(); -} - -LayersTraceFileProto SurfaceTracing::createLayersTraceFileProto() { - LayersTraceFileProto fileProto; - fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | - LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); - return fileProto; -} - -status_t SurfaceTracing::Runner::writeToFile() { - ATRACE_CALL(); - - LayersTraceFileProto fileProto = createLayersTraceFileProto(); - std::string output; - - mBuffer.flush(&fileProto); - mBuffer.reset(mConfig.bufferSize); - - if (!fileProto.SerializeToString(&output)) { - ALOGE("Could not save the proto file! Permission denied"); - return PERMISSION_DENIED; - } - - // -rw-r--r-- - const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - if (!android::base::WriteStringToFile(output, DEFAULT_FILE_NAME, mode, getuid(), getgid(), - true)) { - ALOGE("Could not save the proto file! There are missing fields"); - return PERMISSION_DENIED; - } - - return NO_ERROR; -} - -LayersTraceProto SurfaceTracing::Runner::traceLayers(const char* where) { - ATRACE_CALL(); - - LayersTraceProto entry; - entry.set_elapsed_realtime_nanos(elapsedRealtimeNano()); - entry.set_where(where); - LayersProto layers(mFlinger.dumpDrawingStateProto(mConfig.flags)); - - if (flagIsSet(SurfaceTracing::TRACE_EXTRA)) { - mFlinger.dumpOffscreenLayersProto(layers); - } - entry.mutable_layers()->Swap(&layers); - - if (flagIsSet(SurfaceTracing::TRACE_HWC)) { - std::string hwcDump; - mFlinger.dumpHwc(hwcDump); - entry.set_hwc_blob(hwcDump); - } - if (!flagIsSet(SurfaceTracing::TRACE_COMPOSITION)) { - entry.set_excludes_composition_state(true); - } - entry.set_missed_entries(mMissedTraceEntries); - mFlinger.dumpDisplayProto(entry); - return entry; -} - -void SurfaceTracing::Runner::dump(std::string& result) const { - base::StringAppendF(&result, " number of entries: %zu (%.2fMB / %.2fMB)\n", - mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB), - float(mBuffer.size()) / float(1_MB)); -} - -SurfaceTracing::AsyncRunner::AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, - std::mutex& sfLock) - : SurfaceTracing::Runner(flinger, config), mSfLock(sfLock) { - mEnabled = true; - mThread = std::thread(&AsyncRunner::loop, this); -} - -void SurfaceTracing::AsyncRunner::loop() { - while (mEnabled) { - LayersTraceProto entry; - bool entryAdded = traceWhenNotified(&entry); - if (entryAdded) { - mBuffer.emplace(std::move(entry)); - } - if (mWriteToFile) { - Runner::writeToFile(); - mWriteToFile = false; - } - } -} - -bool SurfaceTracing::AsyncRunner::traceWhenNotified(LayersTraceProto* outProto) { - std::unique_lock lock(mSfLock); - mCanStartTrace.wait(lock); - if (!mAddEntry) { - return false; - } - *outProto = traceLayers(mWhere); - mAddEntry = false; - mMissedTraceEntries = 0; - return true; -} - -void SurfaceTracing::AsyncRunner::notify(const char* where) { - std::scoped_lock lock(mSfLock); - notifyLocked(where); -} - -void SurfaceTracing::AsyncRunner::notifyLocked(const char* where) { - mWhere = where; - if (mAddEntry) { - mMissedTraceEntries++; - } - mAddEntry = true; - mCanStartTrace.notify_one(); -} - -status_t SurfaceTracing::AsyncRunner::writeToFile() { - mWriteToFile = true; - mCanStartTrace.notify_one(); - return STATUS_OK; -} - -status_t SurfaceTracing::AsyncRunner::stop() { - mEnabled = false; - mCanStartTrace.notify_one(); - mThread.join(); - return Runner::writeToFile(); -} - -} // namespace android diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h deleted file mode 100644 index 97adb20c63..0000000000 --- a/services/surfaceflinger/SurfaceTracing.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace android::surfaceflinger; - -namespace android { - -class SurfaceFlinger; -constexpr auto operator""_MB(unsigned long long const num) { - return num * 1024 * 1024; -} -/* - * SurfaceTracing records layer states during surface flinging. Manages tracing state and - * configuration. - */ -class SurfaceTracing { -public: - SurfaceTracing(SurfaceFlinger& flinger); - bool enable(); - bool disable(); - status_t writeToFile(); - bool isEnabled() const; - /* - * Adds a trace entry, must be called from the drawing thread or while holding the - * SurfaceFlinger tracing lock. - */ - void notify(const char* where); - /* - * Adds a trace entry, called while holding the SurfaceFlinger tracing lock. - */ - void notifyLocked(const char* where) /* REQUIRES(mSfLock) */; - - void setBufferSize(size_t bufferSizeInBytes) { mConfig.bufferSize = bufferSizeInBytes; } - void dump(std::string& result) const; - - enum : uint32_t { - TRACE_CRITICAL = 1 << 0, - TRACE_INPUT = 1 << 1, - TRACE_COMPOSITION = 1 << 2, - TRACE_EXTRA = 1 << 3, - TRACE_HWC = 1 << 4, - // Add non-geometry composition changes to the trace. - TRACE_BUFFERS = 1 << 5, - // Add entries from the drawing thread post composition. - TRACE_SYNC = 1 << 6, - TRACE_ALL = TRACE_CRITICAL | TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA, - }; - void setTraceFlags(uint32_t flags) { mConfig.flags = flags; } - bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; } - static LayersTraceFileProto createLayersTraceFileProto(); - -private: - class Runner; - static constexpr auto DEFAULT_BUFFER_SIZE = 20_MB; - static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope"; - - SurfaceFlinger& mFlinger; - mutable std::mutex mTraceLock; - bool mEnabled GUARDED_BY(mTraceLock) = false; - std::unique_ptr runner GUARDED_BY(mTraceLock); - - struct Config { - uint32_t flags = TRACE_CRITICAL | TRACE_INPUT | TRACE_SYNC; - size_t bufferSize = DEFAULT_BUFFER_SIZE; - } mConfig; - - /* - * ring buffer. - */ - class LayersTraceBuffer { - public: - size_t size() const { return mSizeInBytes; } - size_t used() const { return mUsedInBytes; } - size_t frameCount() const { return mStorage.size(); } - - void setSize(size_t newSize) { mSizeInBytes = newSize; } - void reset(size_t newSize); - void emplace(LayersTraceProto&& proto); - void flush(LayersTraceFileProto* fileProto); - - private: - size_t mUsedInBytes = 0U; - size_t mSizeInBytes = DEFAULT_BUFFER_SIZE; - std::queue mStorage; - }; - - /* - * Implements a synchronous way of adding trace entries. This must be called - * from the drawing thread. - */ - class Runner { - public: - Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config); - virtual ~Runner() = default; - virtual status_t stop(); - virtual status_t writeToFile(); - virtual void notify(const char* where); - /* Cannot be called with a synchronous runner. */ - virtual void notifyLocked(const char* /* where */) {} - void dump(std::string& result) const; - - protected: - bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; } - SurfaceFlinger& mFlinger; - SurfaceTracing::Config mConfig; - SurfaceTracing::LayersTraceBuffer mBuffer; - uint32_t mMissedTraceEntries = 0; - LayersTraceProto traceLayers(const char* where); - }; - - /* - * Implements asynchronous way to add trace entries called from a separate thread while holding - * the SurfaceFlinger tracing lock. Trace entries may be missed if the tracing thread is not - * scheduled in time. - */ - class AsyncRunner : public Runner { - public: - AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, std::mutex& sfLock); - virtual ~AsyncRunner() = default; - status_t stop() override; - status_t writeToFile() override; - void notify(const char* where) override; - void notifyLocked(const char* where); - - private: - std::mutex& mSfLock; - std::condition_variable mCanStartTrace; - std::thread mThread; - const char* mWhere = ""; - bool mWriteToFile = false; - bool mEnabled = false; - bool mAddEntry = false; - void loop(); - bool traceWhenNotified(LayersTraceProto* outProto); - }; -}; - -} // namespace android diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp new file mode 100644 index 0000000000..84890eefd1 --- /dev/null +++ b/services/surfaceflinger/Tracing/LayerTracing.cpp @@ -0,0 +1,130 @@ +/* + * 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. + */ + +#undef LOG_TAG +#define LOG_TAG "LayerTracing" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include +#include +#include +#include +#include + +#include "LayerTracing.h" +#include "RingBuffer.h" + +namespace android { + +LayerTracing::LayerTracing(SurfaceFlinger& flinger) : mFlinger(flinger) { + mBuffer = std::make_unique>(); +} + +LayerTracing::~LayerTracing() = default; + +bool LayerTracing::enable() { + std::scoped_lock lock(mTraceLock); + if (mEnabled) { + return false; + } + mBuffer->setSize(mBufferSizeInBytes); + mEnabled = true; + return true; +} + +bool LayerTracing::disable() { + std::scoped_lock lock(mTraceLock); + if (!mEnabled) { + return false; + } + mEnabled = false; + LayersTraceFileProto fileProto = createTraceFileProto(); + mBuffer->writeToFile(fileProto, FILE_NAME); + return true; +} + +bool LayerTracing::isEnabled() const { + std::scoped_lock lock(mTraceLock); + return mEnabled; +} + +status_t LayerTracing::writeToFile() { + std::scoped_lock lock(mTraceLock); + if (!mEnabled) { + return STATUS_OK; + } + LayersTraceFileProto fileProto = createTraceFileProto(); + return mBuffer->writeToFile(fileProto, FILE_NAME); +} + +void LayerTracing::setTraceFlags(uint32_t flags) { + std::scoped_lock lock(mTraceLock); + mFlags = flags; +} + +void LayerTracing::setBufferSize(size_t bufferSizeInBytes) { + std::scoped_lock lock(mTraceLock); + mBufferSizeInBytes = bufferSizeInBytes; +} + +bool LayerTracing::flagIsSet(uint32_t flags) const { + return (mFlags & flags) == flags; +} + +LayersTraceFileProto LayerTracing::createTraceFileProto() const { + LayersTraceFileProto fileProto; + fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | + LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); + return fileProto; +} + +void LayerTracing::dump(std::string& result) const { + std::scoped_lock lock(mTraceLock); + base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled"); + mBuffer->dump(result); +} + +void LayerTracing::notify(const char* where) { + ATRACE_CALL(); + std::scoped_lock lock(mTraceLock); + if (!mEnabled) { + return; + } + + ATRACE_CALL(); + LayersTraceProto entry; + entry.set_elapsed_realtime_nanos(elapsedRealtimeNano()); + entry.set_where(where); + LayersProto layers(mFlinger.dumpDrawingStateProto(mFlags)); + + if (flagIsSet(LayerTracing::TRACE_EXTRA)) { + mFlinger.dumpOffscreenLayersProto(layers); + } + entry.mutable_layers()->Swap(&layers); + + if (flagIsSet(LayerTracing::TRACE_HWC)) { + std::string hwcDump; + mFlinger.dumpHwc(hwcDump); + entry.set_hwc_blob(hwcDump); + } + if (!flagIsSet(LayerTracing::TRACE_COMPOSITION)) { + entry.set_excludes_composition_state(true); + } + mFlinger.dumpDisplayProto(entry); + mBuffer->emplace(std::move(entry)); +} + +} // namespace android diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h new file mode 100644 index 0000000000..8ca3587dbc --- /dev/null +++ b/services/surfaceflinger/Tracing/LayerTracing.h @@ -0,0 +1,77 @@ +/* + * 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 +#include +#include +#include + +#include +#include + +using namespace android::surfaceflinger; + +namespace android { + +template +class RingBuffer; + +class SurfaceFlinger; + +/* + * LayerTracing records layer states during surface flinging. Manages tracing state and + * configuration. + */ +class LayerTracing { +public: + LayerTracing(SurfaceFlinger& flinger); + ~LayerTracing(); + bool enable(); + bool disable(); + bool isEnabled() const; + status_t writeToFile(); + LayersTraceFileProto createTraceFileProto() const; + void notify(const char* where); + + enum : uint32_t { + TRACE_INPUT = 1 << 1, + TRACE_COMPOSITION = 1 << 2, + TRACE_EXTRA = 1 << 3, + TRACE_HWC = 1 << 4, + TRACE_BUFFERS = 1 << 5, + TRACE_ALL = TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA, + }; + void setTraceFlags(uint32_t flags); + bool flagIsSet(uint32_t flags) const; + void setBufferSize(size_t bufferSizeInBytes); + void dump(std::string&) const; + +private: + static constexpr auto FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope"; + + SurfaceFlinger& mFlinger; + uint32_t mFlags = TRACE_INPUT; + mutable std::mutex mTraceLock; + bool mEnabled GUARDED_BY(mTraceLock) = false; + std::unique_ptr> mBuffer + GUARDED_BY(mTraceLock); + size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = 20 * 1024 * 1024; +}; + +} // namespace android diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h new file mode 100644 index 0000000000..d0fb3f28fe --- /dev/null +++ b/services/surfaceflinger/Tracing/RingBuffer.h @@ -0,0 +1,112 @@ +/* + * 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 + +#include +#include +#include +#include +#include + +namespace android { + +class SurfaceFlinger; + +template +class RingBuffer { +public: + size_t size() const { return mSizeInBytes; } + size_t used() const { return mUsedInBytes; } + size_t frameCount() const { return mStorage.size(); } + void setSize(size_t newSize) { mSizeInBytes = newSize; } + EntryProto& front() { return mStorage.front(); } + const EntryProto& front() const { return mStorage.front(); } + + void reset(size_t newSize) { + // use the swap trick to make sure memory is released + std::queue().swap(mStorage); + mSizeInBytes = newSize; + mUsedInBytes = 0U; + } + void flush(FileProto& fileProto) { + fileProto.mutable_entry()->Reserve(static_cast(mStorage.size())); + while (!mStorage.empty()) { + auto entry = fileProto.add_entry(); + entry->Swap(&mStorage.front()); + mStorage.pop(); + } + } + + status_t writeToFile(FileProto& fileProto, std::string filename) { + ATRACE_CALL(); + std::string output; + flush(fileProto); + reset(mSizeInBytes); + if (!fileProto.SerializeToString(&output)) { + ALOGE("Could not serialize proto."); + return UNKNOWN_ERROR; + } + + // -rw-r--r-- + const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + if (!android::base::WriteStringToFile(output, filename, mode, getuid(), getgid(), true)) { + ALOGE("Could not save the proto file."); + return PERMISSION_DENIED; + } + return NO_ERROR; + } + + std::vector emplace(EntryProto&& proto) { + std::vector replacedEntries; + size_t protoSize = static_cast(proto.ByteSize()); + while (mUsedInBytes + protoSize > mSizeInBytes) { + if (mStorage.empty()) { + return {}; + } + mUsedInBytes -= static_cast(mStorage.front().ByteSize()); + replacedEntries.emplace_back(mStorage.front()); + mStorage.pop(); + } + mUsedInBytes += protoSize; + mStorage.emplace(); + mStorage.back().Swap(&proto); + return replacedEntries; + } + + void dump(std::string& result) const { + std::chrono::milliseconds duration(0); + if (frameCount() > 0) { + duration = std::chrono::duration_cast( + std::chrono::nanoseconds(systemTime() - front().elapsed_realtime_nanos())); + } + const int64_t durationCount = duration.count(); + base::StringAppendF(&result, + " number of entries: %zu (%.2fMB / %.2fMB) duration: %" PRIi64 "ms\n", + frameCount(), float(used()) / 1024.f * 1024.f, + float(size()) / 1024.f * 1024.f, durationCount); + } + +private: + size_t mUsedInBytes = 0U; + size_t mSizeInBytes = 0U; + std::queue mStorage; +}; + +} // namespace android -- cgit v1.2.3-59-g8ed1b From a5505cb8fa988023685e8d67fcc8117ee7c63b1e Mon Sep 17 00:00:00 2001 From: Jiakai Zhang Date: Tue, 9 Nov 2021 11:46:30 +0000 Subject: Revert "SurfaceFlinger: Emit callbacks for non-buffer layer transactions" This reverts commit da1fd1508c914c7f0849e4e00a5fae5412433337. Reason for revert: Potential culprit CL for broken test b/205501709 Change-Id: Iece745e0690f4d31b93918697b306ded3abfd0d0 --- services/surfaceflinger/BufferStateLayer.cpp | 15 ++------ services/surfaceflinger/BufferStateLayer.h | 3 +- services/surfaceflinger/Layer.cpp | 11 ------ services/surfaceflinger/Layer.h | 6 ++- services/surfaceflinger/SurfaceFlinger.cpp | 21 +++++----- .../surfaceflinger/TransactionCallbackInvoker.cpp | 8 ++-- .../surfaceflinger/TransactionCallbackInvoker.h | 12 +++--- .../surfaceflinger/tests/LayerCallback_test.cpp | 45 +--------------------- 8 files changed, 32 insertions(+), 89 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 3e09a40eba..c213570c7f 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -549,19 +549,13 @@ bool BufferStateLayer::setSidebandStream(const sp& sidebandStream) } bool BufferStateLayer::setTransactionCompletedListeners( - const std::vector& listenerCallbacks, const sp& layerHandle) { + const std::vector>& handles) { // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return - if (listenerCallbacks.empty()) { + if (handles.empty()) { mReleasePreviousBuffer = false; return false; } - std::vector> handles; - handles.reserve(listenerCallbacks.size()); - for (auto& [listener, callbackIds] : listenerCallbacks) { - handles.emplace_back(new CallbackHandle(listener, callbackIds, layerHandle)); - } - const bool willPresent = willPresentCurrentTransaction(); for (const auto& handle : handles) { @@ -577,10 +571,9 @@ bool BufferStateLayer::setTransactionCompletedListeners( // Store so latched time and release fence can be set mDrawingState.callbackHandles.push_back(handle); - } else { - // If this layer will NOT need to be relatched and presented this frame + } else { // If this layer will NOT need to be relatched and presented this frame // Notify the transaction completed thread this handle is done - mFlinger->getTransactionCallbackInvoker().addUnpresentedCallbackHandle(handle); + mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle); } } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index ceed188f0e..eea700cf7b 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -65,8 +65,7 @@ public: bool setSurfaceDamageRegion(const Region& surfaceDamage) override; bool setApi(int32_t api) override; bool setSidebandStream(const sp& sidebandStream) override; - bool setTransactionCompletedListeners(const std::vector& handles, - const sp& layerHandle) override; + bool setTransactionCompletedListeners(const std::vector>& handles) override; bool addFrameEvent(const sp& acquireFence, nsecs_t postedTime, nsecs_t requestedPresentTime) override; bool setPosition(float /*x*/, float /*y*/) override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d8854d3033..d68cf9720f 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2645,17 +2645,6 @@ bool Layer::setDropInputMode(gui::DropInputMode mode) { return true; } -bool Layer::setTransactionCompletedListeners( - const std::vector& listenerCallbacks, const sp&) { - if (listenerCallbacks.empty()) { - return false; - } - for (auto& listener : listenerCallbacks) { - mFlinger->getTransactionCallbackInvoker().addEmptyCallback(listener); - } - return false; -} - // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index f6f162128f..4569f9af23 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -426,8 +426,10 @@ public: virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; }; virtual bool setApi(int32_t /*api*/) { return false; }; virtual bool setSidebandStream(const sp& /*sidebandStream*/) { return false; }; - virtual bool setTransactionCompletedListeners(const std::vector& /*handles*/, - const sp& /* layerHandle */); + virtual bool setTransactionCompletedListeners( + const std::vector>& /*handles*/) { + return false; + }; virtual bool addFrameEvent(const sp& /*acquireFence*/, nsecs_t /*postedTime*/, nsecs_t /*requestedPresentTime*/) { return false; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index af6d00041e..53a4ae02eb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3727,10 +3727,11 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin transactionFlags |= setDisplayStateLocked(display); } - // Add listeners w/ surfaces so they can get their callback. Note that listeners with - // SurfaceControls will start registration during setClientStateLocked below. + // start and end registration for listeners w/ no surface so they can get their callback. Note + // that listeners with SurfaceControls will start registration during setClientStateLocked + // below. for (const auto& listener : listenerCallbacks) { - mTransactionCallbackInvoker.addEmptyCallback(listener); + mTransactionCallbackInvoker.addEmptyTransaction(listener); } uint32_t clientStateFlags = 0; @@ -3902,7 +3903,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } if (layer == nullptr) { for (auto& [listener, callbackIds] : s.listeners) { - mTransactionCallbackInvoker.addUnpresentedCallbackHandle( + mTransactionCallbackInvoker.registerUnpresentedCallbackHandle( new CallbackHandle(listener, callbackIds, s.surface)); } return 0; @@ -4172,6 +4173,12 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime flags |= eTransactionNeeded | eTraversalNeeded; } } + std::vector> callbackHandles; + if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) { + for (auto& [listener, callbackIds] : filteredListeners) { + callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface)); + } + } if (what & layer_state_t::eBufferChanged && layer->setBuffer(s.bufferData, postTime, desiredPresentTime, isAutoTimestamp, @@ -4181,11 +4188,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime); } - if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) { - if (layer->setTransactionCompletedListeners(filteredListeners, s.surface)) { - flags |= eTraversalNeeded; - } - } + if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; // Do not put anything that updates layer state or modifies flags after // setTransactionCompletedListener return flags; diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index 418fbc5c44..f3d46ea061 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -74,10 +74,10 @@ TransactionCallbackInvoker::~TransactionCallbackInvoker() { } } -void TransactionCallbackInvoker::addEmptyCallback(const ListenerCallbacks& listenerCallbacks) { +void TransactionCallbackInvoker::addEmptyTransaction(const ListenerCallbacks& listenerCallbacks) { auto& [listener, callbackIds] = listenerCallbacks; - TransactionStats* transactionStats; - findOrCreateTransactionStats(listener, callbackIds, &transactionStats); + auto& transactionStatsDeque = mCompletedTransactions[listener]; + transactionStatsDeque.emplace_back(callbackIds); } status_t TransactionCallbackInvoker::addOnCommitCallbackHandles( @@ -116,7 +116,7 @@ status_t TransactionCallbackInvoker::addCallbackHandles( return NO_ERROR; } -status_t TransactionCallbackInvoker::addUnpresentedCallbackHandle( +status_t TransactionCallbackInvoker::registerUnpresentedCallbackHandle( const sp& handle) { return addCallbackHandle(handle, std::vector()); } diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index 6f67947081..e203d41bd9 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -71,10 +71,8 @@ public: // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and // presented this frame. - status_t addUnpresentedCallbackHandle(const sp& handle); - // Adds the callback handles for empty transactions or for non-buffer layer updates which do not - // include layer stats. - void addEmptyCallback(const ListenerCallbacks& listenerCallbacks); + status_t registerUnpresentedCallbackHandle(const sp& handle); + void addEmptyTransaction(const ListenerCallbacks& listenerCallbacks); void addPresentFence(const sp& presentFence); @@ -83,12 +81,14 @@ public: mCompletedTransactions.clear(); } + status_t addCallbackHandle(const sp& handle, + const std::vector& jankData); + + private: status_t findOrCreateTransactionStats(const sp& listener, const std::vector& callbackIds, TransactionStats** outTransactionStats); - status_t addCallbackHandle(const sp& handle, - const std::vector& jankData); std::unordered_map, std::deque, IListenerHash> mCompletedTransactions; diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 7beba15062..91a5b528f8 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -1067,7 +1067,7 @@ TEST_F(LayerCallbackTest, EmptyBufferStateChanges) { } // b202394221 -TEST_F(LayerCallbackTest, NonBufferLayerStateChanges) { +TEST_F(LayerCallbackTest, DISABLED_NonBufferLayerStateChanges) { sp layer; ASSERT_NO_FATAL_FAILURE(layer = createColorLayer("ColorLayer", Color::RED)); @@ -1085,47 +1085,4 @@ TEST_F(LayerCallbackTest, NonBufferLayerStateChanges) { EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); } -class TimedCallbackHelper { -public: - static void function(void* callbackContext, nsecs_t, const sp&, - const std::vector&) { - if (!callbackContext) { - ALOGE("failed to get callback context"); - } - TimedCallbackHelper* helper = static_cast(callbackContext); - std::lock_guard lock(helper->mMutex); - helper->mInvokedTime = systemTime(); - helper->mCv.notify_all(); - } - - void waitForCallback() { - std::unique_lock lock(mMutex); - ASSERT_TRUE(mCv.wait_for(lock, std::chrono::seconds(3), [&] { return mInvokedTime != -1; })) - << "did not receive callback"; - } - void* getContext() { return static_cast(this); } - - std::mutex mMutex; - std::condition_variable mCv; - nsecs_t mInvokedTime = -1; -}; - -TEST_F(LayerCallbackTest, EmptyTransactionCallbackOrder) { - TimedCallbackHelper onCommitCallback; - TimedCallbackHelper onCompleteCallback; - - // Add transaction callback before on commit callback - Transaction() - .addTransactionCompletedCallback(onCompleteCallback.function, - onCompleteCallback.getContext()) - .addTransactionCommittedCallback(onCommitCallback.function, - onCommitCallback.getContext()) - .apply(); - - EXPECT_NO_FATAL_FAILURE(onCompleteCallback.waitForCallback()); - EXPECT_NO_FATAL_FAILURE(onCommitCallback.waitForCallback()); - // verify we get the oncomplete at the same time or after the oncommit callback. - EXPECT_GE(onCompleteCallback.mInvokedTime, onCommitCallback.mInvokedTime); -} - } // namespace android -- cgit v1.2.3-59-g8ed1b From 068173d9076ca25fa5cc008a116e4ec22503b9be Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 11 Aug 2021 17:22:59 -0700 Subject: SF: Add VsyncSchedule skeleton Pull the Scheduler::VsyncSchedule struct and related code into its own file, as it will be extended with more per-display state, e.g. reactor registrations, resync state machine, etc. Add for feature flags. Move Scheduler into its namespace. Bug: 185535769 Test: libsurfaceflinger_unittest Change-Id: I6e10893632c5abf40380df924791d1fcc27c3cc2 --- services/surfaceflinger/Android.bp | 3 +- services/surfaceflinger/BufferQueueLayer.cpp | 5 +- services/surfaceflinger/BufferStateLayer.cpp | 5 +- services/surfaceflinger/DisplayDevice.cpp | 4 +- services/surfaceflinger/DisplayDevice.h | 2 +- services/surfaceflinger/Layer.cpp | 4 +- services/surfaceflinger/Scheduler/LayerHistory.h | 6 +- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 8 +- services/surfaceflinger/Scheduler/Scheduler.cpp | 216 +++++++-------------- services/surfaceflinger/Scheduler/Scheduler.h | 100 ++++------ services/surfaceflinger/Scheduler/VSyncReactor.cpp | 4 +- services/surfaceflinger/Scheduler/VSyncReactor.h | 2 +- .../surfaceflinger/Scheduler/VsyncController.h | 10 +- .../surfaceflinger/Scheduler/VsyncSchedule.cpp | 113 +++++++++++ services/surfaceflinger/Scheduler/VsyncSchedule.h | 75 +++++++ .../Scheduler/include/scheduler/Features.h | 34 ++++ services/surfaceflinger/SurfaceFlinger.cpp | 43 ++-- services/surfaceflinger/SurfaceFlinger.h | 7 +- services/surfaceflinger/SurfaceFlingerFactory.h | 4 - .../tests/unittests/CompositionTest.cpp | 2 +- .../unittests/DisplayDevice_InitiateModeChange.cpp | 2 +- .../unittests/DisplayTransactionTestHelpers.h | 2 +- .../tests/unittests/FpsReporterTest.cpp | 4 + .../tests/unittests/LayerHistoryTest.cpp | 13 +- .../tests/unittests/SchedulerTest.cpp | 43 ++-- .../tests/unittests/SetFrameRateTest.cpp | 2 + .../SurfaceFlinger_NotifyPowerBoostTest.cpp | 7 +- .../tests/unittests/TestableScheduler.h | 39 ++-- .../tests/unittests/TestableSurfaceFlinger.h | 20 +- .../tests/unittests/TransactionApplicationTest.cpp | 5 +- .../tests/unittests/mock/MockSchedulerCallback.h | 17 +- .../tests/unittests/mock/MockVsyncController.h | 2 +- 32 files changed, 461 insertions(+), 342 deletions(-) create mode 100644 services/surfaceflinger/Scheduler/VsyncSchedule.cpp create mode 100644 services/surfaceflinger/Scheduler/VsyncSchedule.h create mode 100644 services/surfaceflinger/Scheduler/include/scheduler/Features.h (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 29636f84f5..c9fb7bc876 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -194,9 +194,10 @@ filegroup { "Scheduler/Timer.cpp", "Scheduler/VSyncDispatchTimerQueue.cpp", "Scheduler/VSyncPredictor.cpp", - "Scheduler/VsyncModulator.cpp", "Scheduler/VSyncReactor.cpp", "Scheduler/VsyncConfiguration.cpp", + "Scheduler/VsyncModulator.cpp", + "Scheduler/VsyncSchedule.cpp", "StartPropertySetThread.cpp", "SurfaceFlinger.cpp", "SurfaceFlingerDefaultFactory.cpp", diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index dec7cc0806..926aa1dfb2 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -372,8 +372,9 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker { // Autolock scope const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp; - mFlinger->mScheduler->recordLayerHistory(this, presentTime, - LayerHistory::LayerUpdateType::Buffer); + + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; + mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer); Mutex::Autolock lock(mQueueItemLock); // Reset the frame number tracker when we receive the first buffer after diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index b4ccb803e9..7d40fc87f9 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -476,8 +476,9 @@ bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime, return static_cast(0); }(); - mFlinger->mScheduler->recordLayerHistory(this, presentTime, - LayerHistory::LayerUpdateType::Buffer); + + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; + mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer); addFrameEvent(mDrawingState.acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index fd09ae4066..76bbe2c58f 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -483,7 +483,7 @@ bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) { std::scoped_lock lock(mActiveModeLock); if (mDesiredActiveModeChanged) { // If a mode change is pending, just cache the latest request in mDesiredActiveMode - const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event; + const auto prevConfig = mDesiredActiveMode.event; mDesiredActiveMode = info; mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig; return false; @@ -508,7 +508,7 @@ std::optional DisplayDevice::getDesiredActiveMode void DisplayDevice::clearDesiredActiveModeState() { std::scoped_lock lock(mActiveModeLock); - mDesiredActiveMode.event = Scheduler::ModeEvent::None; + mDesiredActiveMode.event = scheduler::DisplayModeEvent::None; mDesiredActiveModeChanged = false; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 4b9718f608..324145ef47 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -190,7 +190,7 @@ public: struct ActiveModeInfo { DisplayModePtr mode; - scheduler::RefreshRateConfigEvent event = scheduler::RefreshRateConfigEvent::None; + scheduler::DisplayModeEvent event = scheduler::DisplayModeEvent::None; bool operator!=(const ActiveModeInfo& other) const { return mode != other.mode || event != other.event; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 968a49d526..b3ea94fd94 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1293,8 +1293,8 @@ bool Layer::setFrameRateForLayerTree(FrameRate frameRate) { mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); - mFlinger->mScheduler->recordLayerHistory(this, systemTime(), - LayerHistory::LayerUpdateType::SetFrameRate); + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; + mFlinger->mScheduler->recordLayerHistory(this, systemTime(), LayerUpdateType::SetFrameRate); return true; } diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 92236f560a..8d56951363 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -31,11 +31,9 @@ namespace android { class Layer; -class TestableScheduler; namespace scheduler { -class LayerHistoryTest; class LayerInfo; class LayerHistory { @@ -75,8 +73,8 @@ public: std::string dump() const; private: - friend LayerHistoryTest; - friend TestableScheduler; + friend class LayerHistoryTest; + friend class TestableScheduler; using LayerPair = std::pair>; using LayerInfos = std::vector; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 8a1c2062a6..492feb14df 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -37,11 +37,11 @@ namespace android::scheduler { using namespace std::chrono_literals; -enum class RefreshRateConfigEvent : unsigned { None = 0b0, Changed = 0b1 }; +enum class DisplayModeEvent : unsigned { None = 0b0, Changed = 0b1 }; -inline RefreshRateConfigEvent operator|(RefreshRateConfigEvent lhs, RefreshRateConfigEvent rhs) { - using T = std::underlying_type_t; - return static_cast(static_cast(lhs) | static_cast(rhs)); +inline DisplayModeEvent operator|(DisplayModeEvent lhs, DisplayModeEvent rhs) { + using T = std::underlying_type_t; + return static_cast(static_cast(lhs) | static_cast(rhs)); } using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 4d72798086..cbe4552b0b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -46,11 +46,8 @@ #include "OneShotTimer.h" #include "SchedulerUtils.h" #include "SurfaceFlingerProperties.h" -#include "Timer.h" -#include "VSyncDispatchTimerQueue.h" #include "VSyncPredictor.h" #include "VSyncReactor.h" -#include "VsyncController.h" #define RETURN_IF_INVALID_HANDLE(handle, ...) \ do { \ @@ -60,68 +57,14 @@ } \ } while (false) -using namespace std::string_literals; +namespace android::scheduler { -namespace android { - -using gui::WindowInfo; - -namespace { - -std::unique_ptr createVSyncTracker() { - // TODO(b/144707443): Tune constants. - constexpr int kDefaultRate = 60; - constexpr auto initialPeriod = std::chrono::duration>(1); - constexpr nsecs_t idealPeriod = - std::chrono::duration_cast(initialPeriod).count(); - constexpr size_t vsyncTimestampHistorySize = 20; - constexpr size_t minimumSamplesForPrediction = 6; - constexpr uint32_t discardOutlierPercent = 20; - return std::make_unique(idealPeriod, vsyncTimestampHistorySize, - minimumSamplesForPrediction, - discardOutlierPercent); -} - -std::unique_ptr createVSyncDispatch(scheduler::VSyncTracker& tracker) { - // TODO(b/144707443): Tune constants. - constexpr std::chrono::nanoseconds vsyncMoveThreshold = 3ms; - constexpr std::chrono::nanoseconds timerSlack = 500us; - return std::make_unique< - scheduler::VSyncDispatchTimerQueue>(std::make_unique(), tracker, - timerSlack.count(), vsyncMoveThreshold.count()); -} - -const char* toContentDetectionString(bool useContentDetection) { - return useContentDetection ? "on" : "off"; -} - -} // namespace - -class PredictedVsyncTracer { -public: - PredictedVsyncTracer(scheduler::VSyncDispatch& dispatch) - : mRegistration(dispatch, std::bind(&PredictedVsyncTracer::callback, this), - "PredictedVsyncTracer") { - scheduleRegistration(); - } - -private: - TracedOrdinal mParity = {"VSYNC-predicted", 0}; - scheduler::VSyncCallbackRegistration mRegistration; - - void scheduleRegistration() { mRegistration.schedule({0, 0, 0}); } - - void callback() { - mParity = !mParity; - scheduleRegistration(); - } -}; - -Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, Options options) - : impl::MessageQueue(compositor), mOptions(options), mSchedulerCallback(callback) {} +Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, FeatureFlags features) + : impl::MessageQueue(compositor), mFeatures(features), mSchedulerCallback(callback) {} void Scheduler::startTimers() { using namespace sysprop; + using namespace std::string_literals; if (const int64_t millis = set_touch_timer_ms(0); millis > 0) { // Touch events are coming to SF every 100ms, so the timer needs to be higher than that @@ -154,27 +97,14 @@ void Scheduler::run() { } } -void Scheduler::createVsyncSchedule(bool supportKernelTimer) { - auto clock = std::make_unique(); - auto tracker = createVSyncTracker(); - auto dispatch = createVSyncDispatch(*tracker); - - // TODO(b/144707443): Tune constants. - constexpr size_t pendingFenceLimit = 20; - auto controller = - std::make_unique(std::move(clock), *tracker, pendingFenceLimit, - supportKernelTimer); - mVsyncSchedule = {std::move(controller), std::move(tracker), std::move(dispatch)}; - - if (base::GetBoolProperty("debug.sf.show_predicted_vsync", false)) { - mPredictedVsyncTracer = std::make_unique(*mVsyncSchedule.dispatch); - } +void Scheduler::createVsyncSchedule(FeatureFlags features) { + mVsyncSchedule.emplace(features); } std::unique_ptr Scheduler::makePrimaryDispSyncSource( const char* name, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, bool traceVsync) { - return std::make_unique(*mVsyncSchedule.dispatch, workDuration, + return std::make_unique(getVsyncDispatch(), workDuration, readyDuration, traceVsync, name); } @@ -210,7 +140,7 @@ bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const { return true; } - return mVsyncSchedule.tracker->isVSyncInPhase(expectedVsyncTimestamp, *frameRate); + return mVsyncSchedule->getTracker().isVSyncInPhase(expectedVsyncTimestamp, *frameRate); } impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const { @@ -245,7 +175,7 @@ impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction( }; } -Scheduler::ConnectionHandle Scheduler::createConnection( +ConnectionHandle Scheduler::createConnection( const char* connectionName, frametimeline::TokenManager* tokenManager, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, impl::EventThread::InterceptVSyncsCallback interceptCallback) { @@ -259,7 +189,7 @@ Scheduler::ConnectionHandle Scheduler::createConnection( return createConnection(std::move(eventThread)); } -Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr eventThread) { +ConnectionHandle Scheduler::createConnection(std::unique_ptr eventThread) { const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++}; ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id); @@ -346,24 +276,24 @@ void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDis void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { { - std::lock_guard lock(mFeatureStateLock); + std::lock_guard lock(mPolicyLock); // Cache the last reported modes for primary display. - mFeatures.cachedModeChangedParams = {handle, mode}; + mPolicy.cachedModeChangedParams = {handle, mode}; // Invalidate content based refresh rate selection so it could be calculated // again for the new refresh rate. - mFeatures.contentRequirements.clear(); + mPolicy.contentRequirements.clear(); } onNonPrimaryDisplayModeChanged(handle, mode); } void Scheduler::dispatchCachedReportedMode() { // Check optional fields first. - if (!mFeatures.mode) { + if (!mPolicy.mode) { ALOGW("No mode ID found, not dispatching cached mode."); return; } - if (!mFeatures.cachedModeChangedParams.has_value()) { + if (!mPolicy.cachedModeChangedParams) { ALOGW("No mode changed params found, not dispatching cached mode."); return; } @@ -372,18 +302,18 @@ void Scheduler::dispatchCachedReportedMode() { // mode change is in progress. In that case we shouldn't dispatch an event // as it will be dispatched when the current mode changes. if (std::scoped_lock lock(mRefreshRateConfigsLock); - mRefreshRateConfigs->getCurrentRefreshRate().getMode() != mFeatures.mode) { + mRefreshRateConfigs->getCurrentRefreshRate().getMode() != mPolicy.mode) { return; } // If there is no change from cached mode, there is no need to dispatch an event - if (mFeatures.mode == mFeatures.cachedModeChangedParams->mode) { + if (mPolicy.mode == mPolicy.cachedModeChangedParams->mode) { return; } - mFeatures.cachedModeChangedParams->mode = mFeatures.mode; - onNonPrimaryDisplayModeChanged(mFeatures.cachedModeChangedParams->handle, - mFeatures.cachedModeChangedParams->mode); + mPolicy.cachedModeChangedParams->mode = mPolicy.mode; + onNonPrimaryDisplayModeChanged(mPolicy.cachedModeChangedParams->handle, + mPolicy.cachedModeChangedParams->mode); } void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { @@ -424,12 +354,12 @@ void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds wo } DisplayStatInfo Scheduler::getDisplayStatInfo(nsecs_t now) { - const auto vsyncTime = mVsyncSchedule.tracker->nextAnticipatedVSyncTimeFrom(now); - const auto vsyncPeriod = mVsyncSchedule.tracker->currentPeriod(); + const auto vsyncTime = mVsyncSchedule->getTracker().nextAnticipatedVSyncTimeFrom(now); + const auto vsyncPeriod = mVsyncSchedule->getTracker().currentPeriod(); return DisplayStatInfo{.vsyncTime = vsyncTime, .vsyncPeriod = vsyncPeriod}; } -Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { +ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { if (mInjectVSyncs == enable) { return {}; } @@ -470,7 +400,7 @@ bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime, nsecs_t dea void Scheduler::enableHardwareVsync() { std::lock_guard lock(mHWVsyncLock); if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { - mVsyncSchedule.tracker->resetModel(); + mVsyncSchedule->getTracker().resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } @@ -523,10 +453,10 @@ void Scheduler::resync() { void Scheduler::setVsyncPeriod(nsecs_t period) { std::lock_guard lock(mHWVsyncLock); - mVsyncSchedule.controller->startPeriodTransition(period); + mVsyncSchedule->getController().startPeriodTransition(period); if (!mPrimaryHWVsyncEnabled) { - mVsyncSchedule.tracker->resetModel(); + mVsyncSchedule->getTracker().resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } @@ -539,8 +469,9 @@ void Scheduler::addResyncSample(nsecs_t timestamp, std::optional hwcVsy { // Scope for the lock std::lock_guard lock(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { - needsHwVsync = mVsyncSchedule.controller->addHwVsyncTimestamp(timestamp, hwcVsyncPeriod, - periodFlushed); + needsHwVsync = + mVsyncSchedule->getController().addHwVsyncTimestamp(timestamp, hwcVsyncPeriod, + periodFlushed); } } @@ -551,24 +482,23 @@ void Scheduler::addResyncSample(nsecs_t timestamp, std::optional hwcVsy } } -void Scheduler::addPresentFence(const std::shared_ptr& fenceTime) { - if (mVsyncSchedule.controller->addPresentFence(fenceTime)) { +void Scheduler::addPresentFence(std::shared_ptr fence) { + if (mVsyncSchedule->getController().addPresentFence(std::move(fence))) { enableHardwareVsync(); } else { disableHardwareVsync(false); } } -void Scheduler::setIgnorePresentFences(bool ignore) { - mVsyncSchedule.controller->setIgnorePresentFences(ignore); -} - void Scheduler::registerLayer(Layer* layer) { + using WindowType = gui::WindowInfo::Type; + scheduler::LayerHistory::LayerVoteType voteType; - if (!mOptions.useContentDetection || layer->getWindowType() == WindowInfo::Type::STATUS_BAR) { + if (!mFeatures.test(Feature::kContentDetection) || + layer->getWindowType() == WindowType::STATUS_BAR) { voteType = scheduler::LayerHistory::LayerVoteType::NoVote; - } else if (layer->getWindowType() == WindowInfo::Type::WALLPAPER) { + } else if (layer->getWindowType() == WindowType::WALLPAPER) { // Running Wallpaper at Min is considered as part of content detection. voteType = scheduler::LayerHistory::LayerVoteType::Min; } else { @@ -615,13 +545,13 @@ void Scheduler::chooseRefreshRateForContent() { bool frameRateChanged; bool frameRateOverridesChanged; { - std::lock_guard lock(mFeatureStateLock); - mFeatures.contentRequirements = summary; + std::lock_guard lock(mPolicyLock); + mPolicy.contentRequirements = summary; newMode = calculateRefreshRateModeId(&consideredSignals); frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); - if (mFeatures.mode == newMode) { + if (mPolicy.mode == newMode) { // We don't need to change the display mode, but we might need to send an event // about a mode change, since it was suppressed due to a previous idleConsidered if (!consideredSignals.idle) { @@ -629,15 +559,16 @@ void Scheduler::chooseRefreshRateForContent() { } frameRateChanged = false; } else { - mFeatures.mode = newMode; + mPolicy.mode = newMode; frameRateChanged = true; } } if (frameRateChanged) { - auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + mSchedulerCallback.changeRefreshRate(newRefreshRate, - consideredSignals.idle ? ModeEvent::None - : ModeEvent::Changed); + consideredSignals.idle ? DisplayModeEvent::None + : DisplayModeEvent::Changed); } if (frameRateOverridesChanged) { mSchedulerCallback.triggerOnFrameRateOverridesChanged(); @@ -660,8 +591,8 @@ void Scheduler::onTouchHint() { void Scheduler::setDisplayPowerState(bool normal) { { - std::lock_guard lock(mFeatureStateLock); - mFeatures.isDisplayPowerStateNormal = normal; + std::lock_guard lock(mPolicyLock); + mPolicy.isDisplayPowerStateNormal = normal; } if (mDisplayPowerTimer) { @@ -703,7 +634,7 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { } void Scheduler::idleTimerCallback(TimerState state) { - handleTimerStateChanged(&mFeatures.idleTimer, state); + handleTimerStateChanged(&mPolicy.idleTimer, state); ATRACE_INT("ExpiredIdleTimer", static_cast(state)); } @@ -713,14 +644,14 @@ void Scheduler::touchTimerCallback(TimerState state) { // Clear layer history to get fresh FPS detection. // NOTE: Instead of checking all the layers, we should be checking the layer // that is currently on top. b/142507166 will give us this capability. - if (handleTimerStateChanged(&mFeatures.touch, touch)) { + if (handleTimerStateChanged(&mPolicy.touch, touch)) { mLayerHistory.clear(); } ATRACE_INT("TouchState", static_cast(touch)); } void Scheduler::displayPowerTimerCallback(TimerState state) { - handleTimerStateChanged(&mFeatures.displayPowerTimer, state); + handleTimerStateChanged(&mPolicy.displayPowerTimer, state); ATRACE_INT("ExpiredDisplayPowerTimer", static_cast(state)); } @@ -730,7 +661,7 @@ void Scheduler::dump(std::string& result) const { StringAppendF(&result, "+ Touch timer: %s\n", mTouchTimer ? mTouchTimer->dump().c_str() : "off"); StringAppendF(&result, "+ Content detection: %s %s\n\n", - toContentDetectionString(mOptions.useContentDetection), + mFeatures.test(Feature::kContentDetection) ? "on" : "off", mLayerHistory.dump().c_str()); { @@ -756,13 +687,8 @@ void Scheduler::dump(std::string& result) const { } } -void Scheduler::dumpVsync(std::string& s) const { - using base::StringAppendF; - - StringAppendF(&s, "VSyncReactor:\n"); - mVsyncSchedule.controller->dump(s); - StringAppendF(&s, "VSyncDispatch:\n"); - mVsyncSchedule.dispatch->dump(s); +void Scheduler::dumpVsync(std::string& out) const { + mVsyncSchedule->dump(out); } bool Scheduler::updateFrameRateOverrides( @@ -774,7 +700,7 @@ bool Scheduler::updateFrameRateOverrides( if (!consideredSignals.idle) { const auto frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(mFeatures.contentRequirements, + refreshRateConfigs->getFrameRateOverrides(mPolicy.contentRequirements, displayRefreshRate, consideredSignals); std::lock_guard lock(mFrameRateOverridesLock); if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(), @@ -797,31 +723,30 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { scheduler::RefreshRateConfigs::GlobalSignals consideredSignals; const auto refreshRateConfigs = holdRefreshRateConfigs(); { - std::lock_guard lock(mFeatureStateLock); + std::lock_guard lock(mPolicyLock); if (*currentState == newState) { return false; } *currentState = newState; newMode = calculateRefreshRateModeId(&consideredSignals); frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); - if (mFeatures.mode == newMode) { + if (mPolicy.mode == newMode) { // We don't need to change the display mode, but we might need to send an event // about a mode change, since it was suppressed due to a previous idleConsidered if (!consideredSignals.idle) { dispatchCachedReportedMode(); } } else { - mFeatures.mode = newMode; + mPolicy.mode = newMode; refreshRateChanged = true; } } if (refreshRateChanged) { - const RefreshRate& newRefreshRate = - refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); mSchedulerCallback.changeRefreshRate(newRefreshRate, - consideredSignals.idle ? ModeEvent::None - : ModeEvent::Changed); + consideredSignals.idle ? DisplayModeEvent::None + : DisplayModeEvent::Changed); } if (frameRateOverridesChanged) { mSchedulerCallback.triggerOnFrameRateOverridesChanged(); @@ -838,27 +763,26 @@ DisplayModePtr Scheduler::calculateRefreshRateModeId( // If Display Power is not in normal operation we want to be in performance mode. When coming // back to normal mode, a grace period is given with DisplayPowerTimer. if (mDisplayPowerTimer && - (!mFeatures.isDisplayPowerStateNormal || - mFeatures.displayPowerTimer == TimerState::Reset)) { + (!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) { return refreshRateConfigs->getMaxRefreshRateByPolicy().getMode(); } - const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active; - const bool idle = mFeatures.idleTimer == TimerState::Expired; + const bool touchActive = mTouchTimer && mPolicy.touch == TouchState::Active; + const bool idle = mPolicy.idleTimer == TimerState::Expired; return refreshRateConfigs - ->getBestRefreshRate(mFeatures.contentRequirements, - {.touch = touchActive, .idle = idle}, consideredSignals) + ->getBestRefreshRate(mPolicy.contentRequirements, {.touch = touchActive, .idle = idle}, + consideredSignals) .getMode(); } DisplayModePtr Scheduler::getPreferredDisplayMode() { - std::lock_guard lock(mFeatureStateLock); + std::lock_guard lock(mPolicyLock); // Make sure that the default mode ID is first updated, before returned. - if (mFeatures.mode) { - mFeatures.mode = calculateRefreshRateModeId(); + if (mPolicy.mode) { + mPolicy.mode = calculateRefreshRateModeId(); } - return mFeatures.mode; + return mPolicy.mode; } void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) { @@ -915,8 +839,8 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid std::chrono::steady_clock::time_point Scheduler::getPreviousVsyncFrom( nsecs_t expectedPresentTime) const { const auto presentTime = std::chrono::nanoseconds(expectedPresentTime); - const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule.tracker->currentPeriod()); + const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule->getTracker().currentPeriod()); return std::chrono::steady_clock::time_point(presentTime - vsyncPeriod); } -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 2a6de54e93..e127ff7371 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -31,40 +31,37 @@ #include #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" +#include + #include "EventThread.h" #include "LayerHistory.h" #include "MessageQueue.h" #include "OneShotTimer.h" #include "RefreshRateConfigs.h" #include "SchedulerUtils.h" +#include "VsyncSchedule.h" namespace android { -using namespace std::chrono_literals; -using scheduler::LayerHistory; - class FenceTime; class InjectVSyncSource; -class PredictedVsyncTracer; - -namespace scheduler { -class VsyncController; -class VSyncDispatch; -class VSyncTracker; -} // namespace scheduler namespace frametimeline { class TokenManager; } // namespace frametimeline +namespace scheduler { + struct ISchedulerCallback { // Indicates frame activity, i.e. whether commit and/or composite is taking place. enum class FrameHint { kNone, kActive }; + using RefreshRate = RefreshRateConfigs::RefreshRate; + using DisplayModeEvent = scheduler::DisplayModeEvent; + virtual void scheduleComposite(FrameHint) = 0; virtual void setVsyncEnabled(bool) = 0; - virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, - scheduler::RefreshRateConfigEvent) = 0; + virtual void changeRefreshRate(const RefreshRate&, DisplayModeEvent) = 0; virtual void kernelTimerChanged(bool expired) = 0; virtual void triggerOnFrameRateOverridesChanged() = 0; @@ -76,18 +73,10 @@ class Scheduler : impl::MessageQueue { using Impl = impl::MessageQueue; public: - using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; - using ModeEvent = scheduler::RefreshRateConfigEvent; - - struct Options { - // Whether to use content detection at all. - bool useContentDetection; - }; - - Scheduler(ICompositor&, ISchedulerCallback&, Options); + Scheduler(ICompositor&, ISchedulerCallback&, FeatureFlags); ~Scheduler(); - void createVsyncSchedule(bool supportKernelIdleTimer); + void createVsyncSchedule(FeatureFlags); void startTimers(); void run(); @@ -107,7 +96,6 @@ public: return std::move(future); } - using ConnectionHandle = scheduler::ConnectionHandle; ConnectionHandle createConnection(const char* connectionName, frametimeline::TokenManager*, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, @@ -119,7 +107,7 @@ public: sp getEventConnection(ConnectionHandle); void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected); - void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mFeatureStateLock); + void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mPolicyLock); void onNonPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr); void onScreenAcquired(ConnectionHandle); void onScreenReleased(ConnectionHandle); @@ -152,8 +140,7 @@ public: // VsyncController detected that the vsync period changed, and false otherwise. void addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, bool* periodFlushed); - void addPresentFence(const std::shared_ptr&); - void setIgnorePresentFences(bool ignore); + void addPresentFence(std::shared_ptr); // Layers are registered on creation, and unregistered when the weak reference expires. void registerLayer(Layer*); @@ -172,7 +159,7 @@ public: void setDisplayPowerState(bool normal); - scheduler::VSyncDispatch& getVsyncDispatch() { return *mVsyncSchedule.dispatch; } + VSyncDispatch& getVsyncDispatch() { return mVsyncSchedule->getDispatch(); } // Returns true if a given vsync timestamp is considered valid vsync // for a given uid @@ -211,7 +198,7 @@ public: std::optional getFrameRateOverride(uid_t uid) const EXCLUDES(mRefreshRateConfigsLock, mFrameRateOverridesLock); - void setRefreshRateConfigs(std::shared_ptr refreshRateConfigs) + void setRefreshRateConfigs(std::shared_ptr refreshRateConfigs) EXCLUDES(mRefreshRateConfigsLock) { // We need to stop the idle timer on the previous RefreshRateConfigs instance // and cleanup the scheduler's state before we switch to the other RefreshRateConfigs. @@ -220,8 +207,8 @@ public: if (mRefreshRateConfigs) mRefreshRateConfigs->stopIdleTimer(); } { - std::scoped_lock lock(mFeatureStateLock); - mFeatures = {}; + std::scoped_lock lock(mPolicyLock); + mPolicy = {}; } { std::scoped_lock lock(mRefreshRateConfigsLock); @@ -251,18 +238,10 @@ private: using FrameHint = ISchedulerCallback::FrameHint; - // In order to make sure that the features don't override themselves, we need a state machine - // to keep track which feature requested the config change. enum class ContentDetectionState { Off, On }; enum class TimerState { Reset, Expired }; enum class TouchState { Inactive, Active }; - struct VsyncSchedule { - std::unique_ptr controller; - std::unique_ptr tracker; - std::unique_ptr dispatch; - }; - // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr); sp createConnectionInternal( @@ -284,19 +263,17 @@ private: // selection were initialized, prioritizes them, and calculates the DisplayModeId // for the suggested refresh rate. DisplayModePtr calculateRefreshRateModeId( - scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) - REQUIRES(mFeatureStateLock); + RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) REQUIRES(mPolicyLock); - void dispatchCachedReportedMode() REQUIRES(mFeatureStateLock) EXCLUDES(mRefreshRateConfigsLock); - bool updateFrameRateOverrides(scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, - Fps displayRefreshRate) REQUIRES(mFeatureStateLock) - EXCLUDES(mFrameRateOverridesLock); + void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateConfigsLock); + bool updateFrameRateOverrides(RefreshRateConfigs::GlobalSignals, Fps displayRefreshRate) + REQUIRES(mPolicyLock) EXCLUDES(mFrameRateOverridesLock); impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const EXCLUDES(mRefreshRateConfigsLock); impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const; - std::shared_ptr holdRefreshRateConfigs() const + std::shared_ptr holdRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) { std::scoped_lock lock(mRefreshRateConfigsLock); return mRefreshRateConfigs; @@ -322,66 +299,63 @@ private: std::atomic mLastResyncTime = 0; - const Options mOptions; - VsyncSchedule mVsyncSchedule; + const FeatureFlags mFeatures; + std::optional mVsyncSchedule; // Used to choose refresh rate if content detection is enabled. LayerHistory mLayerHistory; // Timer used to monitor touch events. - std::optional mTouchTimer; + std::optional mTouchTimer; // Timer used to monitor display power mode. - std::optional mDisplayPowerTimer; + std::optional mDisplayPowerTimer; ISchedulerCallback& mSchedulerCallback; - // In order to make sure that the features don't override themselves, we need a state machine - // to keep track which feature requested the config change. - mutable std::mutex mFeatureStateLock; + mutable std::mutex mPolicyLock; struct { + // Policy for choosing the display mode. + LayerHistory::Summary contentRequirements; TimerState idleTimer = TimerState::Reset; TouchState touch = TouchState::Inactive; TimerState displayPowerTimer = TimerState::Expired; + bool isDisplayPowerStateNormal = true; + // Chosen display mode. DisplayModePtr mode; - LayerHistory::Summary contentRequirements; - - bool isDisplayPowerStateNormal = true; - // Used to cache the last parameters of onPrimaryDisplayModeChanged struct ModeChangedParams { ConnectionHandle handle; DisplayModePtr mode; }; + // Parameters for latest dispatch of mode change event. std::optional cachedModeChangedParams; - } mFeatures GUARDED_BY(mFeatureStateLock); + } mPolicy GUARDED_BY(mPolicyLock); mutable std::mutex mRefreshRateConfigsLock; - std::shared_ptr mRefreshRateConfigs - GUARDED_BY(mRefreshRateConfigsLock); + std::shared_ptr mRefreshRateConfigs GUARDED_BY(mRefreshRateConfigsLock); std::mutex mVsyncTimelineLock; std::optional mLastVsyncPeriodChangeTimeline GUARDED_BY(mVsyncTimelineLock); static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms; - std::unique_ptr mPredictedVsyncTracer; - // The frame rate override lists need their own mutex as they are being read // by SurfaceFlinger, Scheduler and EventThread (as a callback) to prevent deadlocks mutable std::mutex mFrameRateOverridesLock; // mappings between a UID and a preferred refresh rate that this app would // run at. - scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesByContent + RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesByContent GUARDED_BY(mFrameRateOverridesLock); - scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor + RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor GUARDED_BY(mFrameRateOverridesLock); // Keeps track of whether the screen is acquired for debug std::atomic mScreenAcquired = false; }; +} // namespace scheduler } // namespace android diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index ee973f718a..1c9de1c452 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -47,7 +47,7 @@ VSyncReactor::VSyncReactor(std::unique_ptr clock, VSyncTracker& tracker, VSyncReactor::~VSyncReactor() = default; -bool VSyncReactor::addPresentFence(const std::shared_ptr& fence) { +bool VSyncReactor::addPresentFence(std::shared_ptr fence) { if (!fence) { return false; } @@ -80,7 +80,7 @@ bool VSyncReactor::addPresentFence(const std::shared_ptr& fe if (mPendingLimit == mUnfiredFences.size()) { mUnfiredFences.erase(mUnfiredFences.begin()); } - mUnfiredFences.push_back(fence); + mUnfiredFences.push_back(std::move(fence)); } else { timestampAccepted &= mTracker.addVsyncTimestamp(signalTime); } diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index 449d4c3bee..a9d536be28 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -37,7 +37,7 @@ public: bool supportKernelIdleTimer); ~VSyncReactor(); - bool addPresentFence(const std::shared_ptr& fence) final; + bool addPresentFence(std::shared_ptr) final; void setIgnorePresentFences(bool ignore) final; void startPeriodTransition(nsecs_t period) final; diff --git a/services/surfaceflinger/Scheduler/VsyncController.h b/services/surfaceflinger/Scheduler/VsyncController.h index 0f0df222f4..59f65372a9 100644 --- a/services/surfaceflinger/Scheduler/VsyncController.h +++ b/services/surfaceflinger/Scheduler/VsyncController.h @@ -17,19 +17,15 @@ #pragma once #include +#include +#include #include #include #include -#include - -#include - namespace android::scheduler { -class FenceTime; - class VsyncController { public: virtual ~VsyncController(); @@ -43,7 +39,7 @@ public: * an accurate prediction, * False otherwise */ - virtual bool addPresentFence(const std::shared_ptr&) = 0; + virtual bool addPresentFence(std::shared_ptr) = 0; /* * Adds a hw sync timestamp to the model. The controller will use the timestamp diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp new file mode 100644 index 0000000000..77d1223aeb --- /dev/null +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp @@ -0,0 +1,113 @@ +/* + * 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 "VsyncSchedule.h" + +#include "Timer.h" +#include "VSyncDispatchTimerQueue.h" +#include "VSyncPredictor.h" +#include "VSyncReactor.h" + +#include "../TracedOrdinal.h" + +namespace android::scheduler { + +class VsyncSchedule::PredictedVsyncTracer { + // Invoked from the thread of the VsyncDispatch owned by this VsyncSchedule. + constexpr auto makeVsyncCallback() { + return [this](nsecs_t, nsecs_t, nsecs_t) { + mParity = !mParity; + schedule(); + }; + } + +public: + explicit PredictedVsyncTracer(VsyncDispatch& dispatch) + : mRegistration(dispatch, makeVsyncCallback(), __func__) { + schedule(); + } + +private: + void schedule() { mRegistration.schedule({0, 0, 0}); } + + TracedOrdinal mParity = {"VSYNC-predicted", 0}; + VSyncCallbackRegistration mRegistration; +}; + +VsyncSchedule::VsyncSchedule(FeatureFlags features) + : mTracker(createTracker()), + mDispatch(createDispatch(*mTracker)), + mController(createController(*mTracker, features)) { + if (features.test(Feature::kTracePredictedVsync)) { + mTracer = std::make_unique(*mDispatch); + } +} + +VsyncSchedule::VsyncSchedule(TrackerPtr tracker, DispatchPtr dispatch, ControllerPtr controller) + : mTracker(std::move(tracker)), + mDispatch(std::move(dispatch)), + mController(std::move(controller)) {} + +VsyncSchedule::VsyncSchedule(VsyncSchedule&&) = default; +VsyncSchedule::~VsyncSchedule() = default; + +void VsyncSchedule::dump(std::string& out) const { + out.append("VsyncController:\n"); + mController->dump(out); + + out.append("VsyncDispatch:\n"); + mDispatch->dump(out); +} + +VsyncSchedule::TrackerPtr VsyncSchedule::createTracker() { + // TODO(b/144707443): Tune constants. + constexpr nsecs_t kInitialPeriod = (60_Hz).getPeriodNsecs(); + constexpr size_t kHistorySize = 20; + constexpr size_t kMinSamplesForPrediction = 6; + constexpr uint32_t kDiscardOutlierPercent = 20; + + return std::make_unique(kInitialPeriod, kHistorySize, kMinSamplesForPrediction, + kDiscardOutlierPercent); +} + +VsyncSchedule::DispatchPtr VsyncSchedule::createDispatch(VsyncTracker& tracker) { + using namespace std::chrono_literals; + + // TODO(b/144707443): Tune constants. + constexpr std::chrono::nanoseconds kGroupDispatchWithin = 500us; + constexpr std::chrono::nanoseconds kSnapToSameVsyncWithin = 3ms; + + return std::make_unique(std::make_unique(), tracker, + kGroupDispatchWithin.count(), + kSnapToSameVsyncWithin.count()); +} + +VsyncSchedule::ControllerPtr VsyncSchedule::createController(VsyncTracker& tracker, + FeatureFlags features) { + // TODO(b/144707443): Tune constants. + constexpr size_t kMaxPendingFences = 20; + const bool hasKernelIdleTimer = features.test(Feature::kKernelIdleTimer); + + auto reactor = std::make_unique(std::make_unique(), tracker, + kMaxPendingFences, hasKernelIdleTimer); + + reactor->setIgnorePresentFences(!features.test(Feature::kPresentFences)); + return reactor; +} + +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h new file mode 100644 index 0000000000..0d9b114875 --- /dev/null +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h @@ -0,0 +1,75 @@ +/* + * 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 + +#include + +namespace android::scheduler { + +// TODO(b/185535769): Rename classes, and remove aliases. +class VSyncDispatch; +class VSyncTracker; + +class VsyncController; +using VsyncDispatch = VSyncDispatch; +using VsyncTracker = VSyncTracker; + +// Schedule that synchronizes to hardware VSYNC of a physical display. +class VsyncSchedule { +public: + explicit VsyncSchedule(FeatureFlags); + VsyncSchedule(VsyncSchedule&&); + ~VsyncSchedule(); + + // TODO(b/185535769): Hide behind API. + const VsyncTracker& getTracker() const { return *mTracker; } + VsyncTracker& getTracker() { return *mTracker; } + VsyncController& getController() { return *mController; } + + // TODO(b/185535769): Remove once VsyncSchedule owns all registrations. + VsyncDispatch& getDispatch() { return *mDispatch; } + + void dump(std::string&) const; + +private: + friend class TestableScheduler; + + using TrackerPtr = std::unique_ptr; + using DispatchPtr = std::unique_ptr; + using ControllerPtr = std::unique_ptr; + + // For tests. + VsyncSchedule(TrackerPtr, DispatchPtr, ControllerPtr); + + static TrackerPtr createTracker(); + static DispatchPtr createDispatch(VsyncTracker&); + static ControllerPtr createController(VsyncTracker&, FeatureFlags); + + class PredictedVsyncTracer; + using TracerPtr = std::unique_ptr; + + // Effectively const except in move constructor. + TrackerPtr mTracker; + DispatchPtr mDispatch; + ControllerPtr mController; + TracerPtr mTracer; +}; + +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Features.h b/services/surfaceflinger/Scheduler/include/scheduler/Features.h new file mode 100644 index 0000000000..0e96678420 --- /dev/null +++ b/services/surfaceflinger/Scheduler/include/scheduler/Features.h @@ -0,0 +1,34 @@ +/* + * 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::scheduler { + +enum class Feature : std::uint8_t { + kPresentFences = 0b1, + kKernelIdleTimer = 0b10, + kContentDetection = 0b100, + kTracePredictedVsync = 0b1000, +}; + +using FeatureFlags = Flags; + +} // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e497d95306..3860901edb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1200,7 +1200,7 @@ void SurfaceFlinger::updateInternalStateWithChangedMode() { mRefreshRateStats->setRefreshRate(refreshRate); updatePhaseConfiguration(refreshRate); - if (upcomingModeInfo.event != Scheduler::ModeEvent::None) { + if (upcomingModeInfo.event != DisplayModeEvent::None) { mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, upcomingModeInfo.mode); } } @@ -3099,7 +3099,7 @@ void SurfaceFlinger::updateCursorAsync() { mCompositionEngine->updateCursorAsync(refreshArgs); } -void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, Scheduler::ModeEvent event) { +void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, DisplayModeEvent event) { // If this is called from the main thread mStateLock must be locked before // Currently the only way to call this function from the main thread is from // Scheduler::chooseRefreshRateForContent @@ -3147,17 +3147,32 @@ void SurfaceFlinger::initScheduler(const sp& display) { mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate); mVsyncModulator = sp::make(mVsyncConfiguration->getCurrentConfigs()); - const Scheduler::Options options = { - .useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}; + using Feature = scheduler::Feature; + scheduler::FeatureFlags features; - mScheduler = std::make_unique(static_cast(*this), - static_cast(*this), options); + if (sysprop::use_content_detection_for_refresh_rate(false)) { + features |= Feature::kContentDetection; + } + if (base::GetBoolProperty("debug.sf.show_predicted_vsync"s, false)) { + features |= Feature::kTracePredictedVsync; + } + if (!base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false) && + !getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) { + features |= Feature::kPresentFences; + } + + mScheduler = std::make_unique(static_cast(*this), + static_cast(*this), + features); { auto configs = display->holdRefreshRateConfigs(); - mScheduler->createVsyncSchedule(configs->supportsKernelIdleTimer()); + if (configs->supportsKernelIdleTimer()) { + features |= Feature::kKernelIdleTimer; + } + + mScheduler->createVsyncSchedule(features); mScheduler->setRefreshRateConfigs(std::move(configs)); } - setVsyncEnabled(false); mScheduler->startTimers(); @@ -3190,11 +3205,6 @@ void SurfaceFlinger::initScheduler(const sp& display) { // classes from EventThread, and there should be no run-time binder cost // anyway since there are no connected apps at this point. mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, display->getActiveMode()); - static auto ignorePresentFences = - base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false); - mScheduler->setIgnorePresentFences( - ignorePresentFences || - getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)); } void SurfaceFlinger::updatePhaseConfiguration(const Fps& refreshRate) { @@ -3818,10 +3828,11 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin clientStateFlags |= setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp, postTime, permissions); if ((flags & eAnimation) && state.state.surface) { - if (const auto layer = fromHandle(state.state.surface).promote(); layer) { + if (const auto layer = fromHandle(state.state.surface).promote()) { + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; mScheduler->recordLayerHistory(layer.get(), isAutoTimestamp ? 0 : desiredPresentTime, - LayerHistory::LayerUpdateType::AnimationTX); + LayerUpdateType::AnimationTX); } } } @@ -6478,7 +6489,7 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) { ALOGV("switching to Scheduler preferred display mode %d", preferredDisplayMode->getId().value()); - setDesiredActiveMode({preferredDisplayMode, Scheduler::ModeEvent::Changed}); + setDesiredActiveMode({preferredDisplayMode, DisplayModeEvent::Changed}); } else { LOG_ALWAYS_FATAL("Desired display mode not allowed: %d", preferredDisplayMode->getId().value()); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 05c058b9af..eb934b6b16 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -165,7 +165,7 @@ class SurfaceFlinger : public BnSurfaceComposer, private IBinder::DeathRecipient, private HWC2::ComposerCallback, private ICompositor, - private ISchedulerCallback { + private scheduler::ISchedulerCallback { public: struct SkipInitializationTag {}; @@ -356,7 +356,6 @@ private: friend class TransactionApplicationTest; friend class TunnelModeEnabledReporterTest; - using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using VsyncModulator = scheduler::VsyncModulator; using TransactionSchedule = scheduler::TransactionSchedule; using TraverseLayersFunction = std::function; @@ -643,7 +642,7 @@ private: // Toggles hardware VSYNC by calling into HWC. void setVsyncEnabled(bool) override; // Initiates a refresh rate change to be applied on commit. - void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override; + void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override; // Called when kernel idle timer has expired. Used to update the refresh rate overlay. void kernelTimerChanged(bool expired) override; // Called when the frame rate override list changed to trigger an event. @@ -1261,7 +1260,7 @@ private: /* * Scheduler */ - std::unique_ptr mScheduler; + std::unique_ptr mScheduler; scheduler::ConnectionHandle mAppConnectionHandle; scheduler::ConnectionHandle mSfConnectionHandle; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index e509cc9385..6153e8e354 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -42,16 +42,12 @@ class HWComposer; class IGraphicBufferConsumer; class IGraphicBufferProducer; class Layer; -class MessageQueue; -class Scheduler; class StartPropertySetThread; class SurfaceFlinger; class SurfaceInterceptor; class TimeStats; struct DisplayDeviceCreationArgs; -struct ICompositor; -struct ISchedulerCallback; struct LayerCreationArgs; namespace compositionengine { diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 8d2c078305..eb5f31e796 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -138,7 +138,7 @@ public: .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - constexpr ISchedulerCallback* kCallback = nullptr; + constexpr scheduler::ISchedulerCallback* kCallback = nullptr; constexpr bool kHasMultipleConfigs = true; mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), std::move(sfEventThread), kCallback, diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp index d4cfbbbe0c..5a0033ea7e 100644 --- a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp @@ -29,7 +29,7 @@ using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjec class InitiateModeChangeTest : public DisplayTransactionTest { public: - using Event = scheduler::RefreshRateConfigEvent; + using Event = scheduler::DisplayModeEvent; void SetUp() override { injectFakeBufferQueueFactory(); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index de5e9dfb97..0a3437aab9 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -121,7 +121,7 @@ public: mock::VsyncController* mVsyncController = new mock::VsyncController; mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker; - mock::SchedulerCallback mSchedulerCallback; + scheduler::mock::SchedulerCallback mSchedulerCallback; mock::EventThread* mEventThread = new mock::EventThread; mock::EventThread* mSFEventThread = new mock::EventThread; diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp index cd2fc7426e..bb1f4328b5 100644 --- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp @@ -17,6 +17,8 @@ #undef LOG_TAG #define LOG_TAG "FpsReporterTest" +#include + #include #include #include @@ -36,6 +38,8 @@ namespace android { +using namespace std::chrono_literals; + using testing::_; using testing::DoAll; using testing::Mock; diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 4993a2d8bc..00687ad4b6 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -38,9 +38,9 @@ using testing::_; using testing::Return; using testing::ReturnRef; -namespace android { +namespace android::scheduler { -namespace scheduler { +using MockLayer = android::mock::MockLayer; class LayerHistoryTest : public testing::Test { protected: @@ -93,12 +93,12 @@ protected: } } - auto createLayer() { return sp(new mock::MockLayer(mFlinger.flinger())); } + auto createLayer() { return sp::make(mFlinger.flinger()); } auto createLayer(std::string name) { - return sp(new mock::MockLayer(mFlinger.flinger(), std::move(name))); + return sp::make(mFlinger.flinger(), std::move(name)); } - void recordFramesAndExpect(const sp& layer, nsecs_t& time, Fps frameRate, + void recordFramesAndExpect(const sp& layer, nsecs_t& time, Fps frameRate, Fps desiredRefreshRate, int numFrames) { LayerHistory::Summary summary; for (int i = 0; i < numFrames; i++) { @@ -768,8 +768,7 @@ INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryTestParameterized, ::testing::Values(1s, 2s, 3s, 4s, 5s)); } // namespace -} // namespace scheduler -} // namespace android +} // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index e558f3b700..a6fd378d3d 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -28,12 +28,16 @@ #include "mock/MockLayer.h" #include "mock/MockSchedulerCallback.h" +namespace android::scheduler { + using testing::_; using testing::Return; -namespace android { namespace { +using MockEventThread = android::mock::EventThread; +using MockLayer = android::mock::MockLayer; + constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = PhysicalDisplayId::fromPort(255u); class SchedulerTest : public testing::Test { @@ -64,21 +68,21 @@ protected: .setGroup(0) .build(); - std::shared_ptr mConfigs = - std::make_shared(DisplayModes{mode60}, mode60->getId()); + std::shared_ptr mConfigs = + std::make_shared(DisplayModes{mode60}, mode60->getId()); mock::SchedulerCallback mSchedulerCallback; TestableScheduler* mScheduler = new TestableScheduler{mConfigs, mSchedulerCallback}; - Scheduler::ConnectionHandle mConnectionHandle; - mock::EventThread* mEventThread; + ConnectionHandle mConnectionHandle; + MockEventThread* mEventThread; sp mEventThreadConnection; TestableSurfaceFlinger mFlinger; }; SchedulerTest::SchedulerTest() { - auto eventThread = std::make_unique(); + auto eventThread = std::make_unique(); mEventThread = eventThread.get(); EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0)); @@ -98,7 +102,7 @@ SchedulerTest::SchedulerTest() { } // namespace TEST_F(SchedulerTest, invalidConnectionHandle) { - Scheduler::ConnectionHandle handle; + ConnectionHandle handle; const sp connection = mScheduler->createDisplayEventConnection(handle); @@ -155,7 +159,7 @@ TEST_F(SchedulerTest, validConnectionHandle) { TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSupported) { // The layer is registered at creation time and deregistered at destruction time. - sp layer = sp::make(mFlinger.flinger()); + sp layer = sp::make(mFlinger.flinger()); // recordLayerHistory should be a noop ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); @@ -174,24 +178,22 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSup TEST_F(SchedulerTest, updateDisplayModes) { ASSERT_EQ(0u, mScheduler->layerHistorySize()); - sp layer = sp::make(mFlinger.flinger()); + sp layer = sp::make(mFlinger.flinger()); ASSERT_EQ(1u, mScheduler->layerHistorySize()); mScheduler->setRefreshRateConfigs( - std::make_shared(DisplayModes{mode60, mode120}, - mode60->getId())); + std::make_shared(DisplayModes{mode60, mode120}, mode60->getId())); ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); ASSERT_EQ(1u, mScheduler->getNumActiveLayers()); } -TEST_F(SchedulerTest, testDispatchCachedReportedMode) { - // If the optional fields are cleared, the function should return before - // onModeChange is called. - mScheduler->clearOptionalFieldsInFeatures(); - EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode()); +TEST_F(SchedulerTest, dispatchCachedReportedMode) { + mScheduler->clearCachedReportedMode(); + EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0); + EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode()); } TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) { @@ -203,7 +205,7 @@ TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) { // If the handle is incorrect, the function should return before // onModeChange is called. - Scheduler::ConnectionHandle invalidHandle = {.id = 123}; + ConnectionHandle invalidHandle = {.id = 123}; EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle, mode)); EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0); } @@ -224,10 +226,9 @@ MATCHER(Is120Hz, "") { TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->setRefreshRateConfigs( - std::make_shared(DisplayModes{mode60, mode120}, - mode60->getId())); + std::make_shared(DisplayModes{mode60, mode120}, mode60->getId())); - sp layer = sp::make(mFlinger.flinger()); + sp layer = sp::make(mFlinger.flinger()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); @@ -241,4 +242,4 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->chooseRefreshRateForContent(); } -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index eed62a70c3..fe5f9e0717 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -48,6 +48,8 @@ using android::Hwc2::IComposerClient; using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; +using scheduler::LayerHistory; + using FrameRate = Layer::FrameRate; using FrameRateCompatibility = Layer::FrameRateCompatibility; diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp index 69e0501bd6..ec7e8a7f82 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp @@ -17,6 +17,9 @@ #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" +#include +#include + #include "DisplayTransactionTestHelpers.h" #include @@ -27,6 +30,8 @@ namespace { using android::hardware::power::Boost; TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) { + using namespace std::chrono_literals; + mFlinger.scheduler()->replaceTouchTimer(100); std::this_thread::sleep_for(10ms); // wait for callback to be triggered EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch @@ -47,4 +52,4 @@ TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) { } } // namespace -} // namespace android \ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 9d1fc981aa..dabd2d2cc2 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -28,22 +28,20 @@ #include "mock/MockVSyncTracker.h" #include "mock/MockVsyncController.h" -namespace android { +namespace android::scheduler { class TestableScheduler : public Scheduler, private ICompositor { public: - TestableScheduler(std::shared_ptr configs, - ISchedulerCallback& callback) + TestableScheduler(std::shared_ptr configs, ISchedulerCallback& callback) : TestableScheduler(std::make_unique(), std::make_unique(), std::move(configs), callback) {} - TestableScheduler(std::unique_ptr vsyncController, - std::unique_ptr vsyncTracker, - std::shared_ptr configs, - ISchedulerCallback& callback) - : Scheduler(*this, callback, {.useContentDetection = true}) { - mVsyncSchedule = {std::move(vsyncController), std::move(vsyncTracker), nullptr}; + TestableScheduler(std::unique_ptr controller, + std::unique_ptr tracker, + std::shared_ptr configs, ISchedulerCallback& callback) + : Scheduler(*this, callback, Feature::kContentDetection) { + mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker), nullptr, std::move(controller))); setRefreshRateConfigs(std::move(configs)); ON_CALL(*this, postMessage).WillByDefault([](sp&& handler) { @@ -86,33 +84,24 @@ public: } bool isTouchActive() { - std::lock_guard lock(mFeatureStateLock); - return mFeatures.touch == Scheduler::TouchState::Active; + std::lock_guard lock(mPolicyLock); + return mPolicy.touch == Scheduler::TouchState::Active; } void dispatchCachedReportedMode() { - std::lock_guard lock(mFeatureStateLock); + std::lock_guard lock(mPolicyLock); return Scheduler::dispatchCachedReportedMode(); } - void clearOptionalFieldsInFeatures() { - std::lock_guard lock(mFeatureStateLock); - mFeatures.cachedModeChangedParams.reset(); + void clearCachedReportedMode() { + std::lock_guard lock(mPolicyLock); + mPolicy.cachedModeChangedParams.reset(); } void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { return Scheduler::onNonPrimaryDisplayModeChanged(handle, mode); } - ~TestableScheduler() { - // All these pointer and container clears help ensure that GMock does - // not report a leaked object, since the Scheduler instance may - // still be referenced by something despite our best efforts to destroy - // it after each test is done. - mVsyncSchedule.controller.reset(); - mConnections.clear(); - } - private: // ICompositor overrides: bool commit(nsecs_t, int64_t, nsecs_t) override { return false; } @@ -120,4 +109,4 @@ private: void sample() override {} }; -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 4c5789e47f..4473e01c2b 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -169,12 +169,12 @@ public: } // namespace surfaceflinger::test -class TestableSurfaceFlinger final : private ISchedulerCallback { +class TestableSurfaceFlinger final : private scheduler::ISchedulerCallback { public: using HotplugEvent = SurfaceFlinger::HotplugEvent; SurfaceFlinger* flinger() { return mFlinger.get(); } - TestableScheduler* scheduler() { return mScheduler; } + scheduler::TestableScheduler* scheduler() { return mScheduler; } // Extend this as needed for accessing SurfaceFlinger private (and public) // functions. @@ -197,7 +197,8 @@ public: std::unique_ptr vsyncTracker, std::unique_ptr appEventThread, std::unique_ptr sfEventThread, - ISchedulerCallback* callback = nullptr, bool hasMultipleModes = false) { + scheduler::ISchedulerCallback* callback = nullptr, + bool hasMultipleModes = false) { DisplayModes modes{DisplayMode::Builder(0) .setId(DisplayModeId(0)) .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) @@ -224,17 +225,18 @@ public: std::make_unique(*mFlinger->mTimeStats, currFps, /*powerMode=*/hal::PowerMode::OFF); - mScheduler = new TestableScheduler(std::move(vsyncController), std::move(vsyncTracker), - mRefreshRateConfigs, *(callback ?: this)); + mScheduler = new scheduler::TestableScheduler(std::move(vsyncController), + std::move(vsyncTracker), mRefreshRateConfigs, + *(callback ?: this)); mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread)); mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread)); resetScheduler(mScheduler); } - void resetScheduler(Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); } + void resetScheduler(scheduler::Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); } - TestableScheduler& mutableScheduler() const { return *mScheduler; } + scheduler::TestableScheduler& mutableScheduler() const { return *mScheduler; } using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction; void setCreateBufferQueueFunction(CreateBufferQueueFunction f) { @@ -759,13 +761,13 @@ public: private: void scheduleComposite(FrameHint) override {} void setVsyncEnabled(bool) override {} - void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override {} + void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override {} void kernelTimerChanged(bool) override {} void triggerOnFrameRateOverridesChanged() {} surfaceflinger::test::Factory mFactory; sp mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization); - TestableScheduler* mScheduler = nullptr; + scheduler::TestableScheduler* mScheduler = nullptr; std::shared_ptr mRefreshRateConfigs; }; diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index ec19100c2b..16d4b59250 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -26,7 +26,7 @@ #include #include #include -#include "TestableScheduler.h" + #include "TestableSurfaceFlinger.h" #include "mock/MockEventThread.h" #include "mock/MockVsyncController.h" @@ -85,11 +85,8 @@ public: std::move(eventThread), std::move(sfEventThread)); } - TestableScheduler* mScheduler; TestableSurfaceFlinger mFlinger; - std::unique_ptr mEventThread = std::make_unique(); - mock::VsyncController* mVsyncController = new mock::VsyncController(); mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker(); mock::MockFence* mFenceUnsignaled = new mock::MockFence(); diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h index e241dc903f..849e3083c4 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h +++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h @@ -20,25 +20,22 @@ #include "Scheduler/Scheduler.h" -namespace android::mock { +namespace android::scheduler::mock { struct SchedulerCallback final : ISchedulerCallback { MOCK_METHOD(void, scheduleComposite, (FrameHint), (override)); - MOCK_METHOD1(setVsyncEnabled, void(bool)); - MOCK_METHOD2(changeRefreshRate, - void(const scheduler::RefreshRateConfigs::RefreshRate&, - scheduler::RefreshRateConfigEvent)); - MOCK_METHOD1(kernelTimerChanged, void(bool)); - MOCK_METHOD0(triggerOnFrameRateOverridesChanged, void()); + MOCK_METHOD(void, setVsyncEnabled, (bool), (override)); + MOCK_METHOD(void, changeRefreshRate, (const RefreshRate&, DisplayModeEvent), (override)); + MOCK_METHOD(void, kernelTimerChanged, (bool), (override)); + MOCK_METHOD(void, triggerOnFrameRateOverridesChanged, (), (override)); }; struct NoOpSchedulerCallback final : ISchedulerCallback { void scheduleComposite(FrameHint) override {} void setVsyncEnabled(bool) override {} - void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, - scheduler::RefreshRateConfigEvent) override {} + void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override {} void kernelTimerChanged(bool) override {} void triggerOnFrameRateOverridesChanged() {} }; -} // namespace android::mock +} // namespace android::scheduler::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h index 94d99665ce..314f681545 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h +++ b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h @@ -27,7 +27,7 @@ public: VsyncController(); ~VsyncController() override; - MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr&)); + MOCK_METHOD(bool, addPresentFence, (std::shared_ptr), (override)); MOCK_METHOD3(addHwVsyncTimestamp, bool(nsecs_t, std::optional, bool*)); MOCK_METHOD1(startPeriodTransition, void(nsecs_t)); MOCK_METHOD1(setIgnorePresentFences, void(bool)); -- cgit v1.2.3-59-g8ed1b From f5d0ea545aaea01d8d73ad97603619ec3874a2e7 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sun, 26 Sep 2021 17:27:01 -0700 Subject: SF: Remove manual enum stringification Upgrade to scoped enums where applicable. Pull GameMode from TimeStats into libgui to plumb it as an enum rather than int32_t. Bug: 185536303 Test: libsurfaceflinger_unittest Change-Id: I81fdd24805757ef953484055ee867684eb94fecf --- libs/gui/include/gui/LayerMetadata.h | 10 + services/surfaceflinger/BufferLayer.cpp | 14 +- .../include/compositionengine/DisplaySurface.h | 11 +- .../CompositionEngine/src/RenderSurface.cpp | 19 +- .../CompositionEngine/tests/RenderSurfaceTest.cpp | 8 +- .../DisplayHardware/VirtualDisplaySurface.cpp | 242 ++++++++------------- .../DisplayHardware/VirtualDisplaySurface.h | 64 +++--- .../surfaceflinger/FrameTimeline/FrameTimeline.cpp | 4 +- .../surfaceflinger/FrameTimeline/FrameTimeline.h | 9 +- services/surfaceflinger/Layer.cpp | 34 +-- services/surfaceflinger/Layer.h | 18 +- services/surfaceflinger/Scheduler/LayerInfo.cpp | 7 +- services/surfaceflinger/Scheduler/LayerInfo.h | 2 + .../Scheduler/RefreshRateConfigs.cpp | 35 +-- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 4 +- services/surfaceflinger/Scheduler/Timer.cpp | 31 +-- services/surfaceflinger/Scheduler/Timer.h | 13 +- .../Scheduler/include/scheduler/Seamlessness.h | 22 +- services/surfaceflinger/SurfaceFlinger.cpp | 7 +- services/surfaceflinger/TimeStats/TimeStats.cpp | 24 +- services/surfaceflinger/TimeStats/TimeStats.h | 26 +-- .../TimeStats/timestatsproto/TimeStatsHelper.cpp | 45 +--- .../include/timestatsproto/TimeStatsHelper.h | 27 +-- .../tests/unittests/CompositionTest.cpp | 4 +- .../tests/unittests/FrameTimelineTest.cpp | 15 +- .../tests/unittests/GameModeTest.cpp | 41 ++-- .../tests/unittests/RefreshRateConfigsTest.cpp | 5 +- .../tests/unittests/TimeStatsTest.cpp | 74 +++---- .../tests/unittests/mock/MockTimeStats.h | 16 +- 29 files changed, 346 insertions(+), 485 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h index de14b3d785..27f4d379e9 100644 --- a/libs/gui/include/gui/LayerMetadata.h +++ b/libs/gui/include/gui/LayerMetadata.h @@ -59,4 +59,14 @@ struct LayerMetadata : public Parcelable { std::string itemToString(uint32_t key, const char* separator) const; }; +// Keep in sync with the GameManager.java constants. +enum class GameMode : int32_t { + Unsupported = 0, + Standard = 1, + Performance = 2, + Battery = 3, + + ftl_last = Battery +}; + } // namespace android diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 861d4963f7..490775faec 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -401,12 +401,13 @@ void BufferLayer::onPostComposition(const DisplayDevice* display, const Fps refreshRate = display->refreshRateConfigs().getCurrentRefreshRate().getFps(); const std::optional renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); + + const auto vote = frameRateToSetFrameRateVotePayload(mDrawingState.frameRate); + const auto gameMode = getGameMode(); + if (presentFence->isValid()) { mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence, - refreshRate, renderRate, - frameRateToSetFrameRateVotePayload( - mDrawingState.frameRate), - getGameMode()); + refreshRate, renderRate, vote, gameMode); mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, presentFence, FrameTracer::FrameEvent::PRESENT_FENCE); @@ -417,10 +418,7 @@ void BufferLayer::onPostComposition(const DisplayDevice* display, // timestamp instead. const nsecs_t actualPresentTime = display->getRefreshTimestamp(); mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime, - refreshRate, renderRate, - frameRateToSetFrameRateVotePayload( - mDrawingState.frameRate), - getGameMode()); + refreshRate, renderRate, vote, gameMode); mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, actualPresentTime, FrameTracer::FrameEvent::PRESENT_FENCE); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h index 4502eee97c..c553fce85d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h @@ -16,6 +16,8 @@ #pragma once +#include + #include #include #include @@ -47,13 +49,8 @@ public: // before composition takes place. The DisplaySurface can use the // composition type to decide how to manage the flow of buffers between // GPU and HWC for this frame. - enum CompositionType { - COMPOSITION_UNKNOWN = 0, - COMPOSITION_GPU = 1, - COMPOSITION_HWC = 2, - COMPOSITION_MIXED = COMPOSITION_GPU | COMPOSITION_HWC - }; - virtual status_t prepareFrame(CompositionType compositionType) = 0; + enum class CompositionType : uint8_t { Unknown = 0, Gpu = 0b1, Hwc = 0b10, Mixed = Gpu | Hwc }; + virtual status_t prepareFrame(CompositionType) = 0; // Inform the surface that GPU composition is complete for this frame, and // the surface should make sure that HWComposer has the correct buffer for diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index ef50870615..a19d23febf 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -127,19 +127,18 @@ status_t RenderSurface::beginFrame(bool mustRecompose) { } void RenderSurface::prepareFrame(bool usesClientComposition, bool usesDeviceComposition) { - DisplaySurface::CompositionType compositionType; - if (usesClientComposition && usesDeviceComposition) { - compositionType = DisplaySurface::COMPOSITION_MIXED; - } else if (usesClientComposition) { - compositionType = DisplaySurface::COMPOSITION_GPU; - } else if (usesDeviceComposition) { - compositionType = DisplaySurface::COMPOSITION_HWC; - } else { + const auto compositionType = [=] { + using CompositionType = DisplaySurface::CompositionType; + + if (usesClientComposition && usesDeviceComposition) return CompositionType::Mixed; + if (usesClientComposition) return CompositionType::Gpu; + if (usesDeviceComposition) return CompositionType::Hwc; + // Nothing to do -- when turning the screen off we get a frame like // this. Call it a HWC frame since we won't be doing any GPU work but // will do a prepare/set cycle. - compositionType = DisplaySurface::COMPOSITION_HWC; - } + return CompositionType::Hwc; + }(); if (status_t result = mDisplaySurface->prepareFrame(compositionType); result != NO_ERROR) { ALOGE("updateCompositionType failed for %s: %d (%s)", mDisplay.getName().c_str(), result, diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 431cc93514..7c8e41b53e 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -201,28 +201,28 @@ TEST_F(RenderSurfaceTest, beginFrameAppliesChange) { */ TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) { - EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED)) + EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::CompositionType::Mixed)) .WillOnce(Return(NO_ERROR)); mSurface.prepareFrame(true, true); } TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGpuComposition) { - EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GPU)) + EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::CompositionType::Gpu)) .WillOnce(Return(NO_ERROR)); mSurface.prepareFrame(true, false); } TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) { - EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)) + EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::CompositionType::Hwc)) .WillOnce(Return(NO_ERROR)); mSurface.prepareFrame(false, true); } TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) { - EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)) + EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::CompositionType::Hwc)) .WillOnce(Return(NO_ERROR)); mSurface.prepareFrame(false, false); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 82a9ae2578..b4fb51f9d5 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -21,20 +21,18 @@ // #define LOG_NDEBUG 0 #include "VirtualDisplaySurface.h" -#include +#include #include "HWComposer.h" #include "SurfaceFlinger.h" +#include +#include #include #include #include #include -// --------------------------------------------------------------------------- -namespace android { -// --------------------------------------------------------------------------- - #define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \ mDisplayName.c_str(), ##__VA_ARGS__) #define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \ @@ -42,20 +40,11 @@ namespace android { #define VDS_LOGV(msg, ...) ALOGV("[%s] " msg, \ mDisplayName.c_str(), ##__VA_ARGS__) -static const char* dbgCompositionTypeStr(compositionengine::DisplaySurface::CompositionType type) { - switch (type) { - case compositionengine::DisplaySurface::COMPOSITION_UNKNOWN: - return "UNKNOWN"; - case compositionengine::DisplaySurface::COMPOSITION_GPU: - return "GPU"; - case compositionengine::DisplaySurface::COMPOSITION_HWC: - return "HWC"; - case compositionengine::DisplaySurface::COMPOSITION_MIXED: - return "MIXED"; - default: - return ""; - } -} +#define UNSUPPORTED() \ + VDS_LOGE("%s: Invalid operation on virtual display", __func__); \ + return INVALID_OPERATION + +namespace android { VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, VirtualDisplayId displayId, const sp& sink, @@ -76,14 +65,10 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, VirtualDisplayId d mQueueBufferOutput(), mSinkBufferWidth(0), mSinkBufferHeight(0), - mCompositionType(COMPOSITION_UNKNOWN), mFbFence(Fence::NO_FENCE), mOutputFence(Fence::NO_FENCE), mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT), mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT), - mDbgState(DBG_STATE_IDLE), - mDbgLastCompositionType(COMPOSITION_UNKNOWN), - mMustRecompose(false), mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv) { mSource[SOURCE_SINK] = sink; mSource[SOURCE_SCRATCH] = bqProducer; @@ -131,9 +116,9 @@ status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) { mMustRecompose = mustRecompose; - VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE, - "Unexpected beginFrame() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_BEGUN; + VDS_LOGW_IF(mDebugState != DebugState::Idle, "Unexpected %s in %s state", __func__, + ftl::enum_string(mDebugState).c_str()); + mDebugState = DebugState::Begun; return refreshOutputBuffer(); } @@ -143,12 +128,12 @@ status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { return NO_ERROR; } - VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN, - "Unexpected prepareFrame() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_PREPARED; + VDS_LOGW_IF(mDebugState != DebugState::Begun, "Unexpected %s in %s state", __func__, + ftl::enum_string(mDebugState).c_str()); + mDebugState = DebugState::Prepared; mCompositionType = compositionType; - if (mForceHwcCopy && mCompositionType == COMPOSITION_GPU) { + if (mForceHwcCopy && mCompositionType == CompositionType::Gpu) { // Some hardware can do RGB->YUV conversion more efficiently in hardware // controlled by HWC than in hardware controlled by the video encoder. // Forcing GPU-composed frames to go through an extra copy by the HWC @@ -157,16 +142,16 @@ status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { // // On the other hand, when the consumer prefers RGB or can consume RGB // inexpensively, this forces an unnecessary copy. - mCompositionType = COMPOSITION_MIXED; + mCompositionType = CompositionType::Mixed; } - if (mCompositionType != mDbgLastCompositionType) { - VDS_LOGV("prepareFrame: composition type changed to %s", - dbgCompositionTypeStr(mCompositionType)); - mDbgLastCompositionType = mCompositionType; + if (mCompositionType != mDebugLastCompositionType) { + VDS_LOGV("%s: composition type changed to %s", __func__, + toString(mCompositionType).c_str()); + mDebugLastCompositionType = mCompositionType; } - if (mCompositionType != COMPOSITION_GPU && + if (mCompositionType != CompositionType::Gpu && (mOutputFormat != mDefaultOutputFormat || mOutputUsage != GRALLOC_USAGE_HW_COMPOSER)) { // We must have just switched from GPU-only to MIXED or HWC // composition. Stop using the format and usage requested by the GPU @@ -191,33 +176,32 @@ status_t VirtualDisplaySurface::advanceFrame() { return NO_ERROR; } - if (mCompositionType == COMPOSITION_HWC) { - VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, - "Unexpected advanceFrame() in %s state on HWC frame", - dbgStateStr()); + if (mCompositionType == CompositionType::Hwc) { + VDS_LOGW_IF(mDebugState != DebugState::Prepared, "Unexpected %s in %s state on HWC frame", + __func__, ftl::enum_string(mDebugState).c_str()); } else { - VDS_LOGW_IF(mDbgState != DBG_STATE_GPU_DONE, - "Unexpected advanceFrame() in %s state on GPU/MIXED frame", dbgStateStr()); + VDS_LOGW_IF(mDebugState != DebugState::GpuDone, + "Unexpected %s in %s state on GPU/MIXED frame", __func__, + ftl::enum_string(mDebugState).c_str()); } - mDbgState = DBG_STATE_HWC; + mDebugState = DebugState::Hwc; if (mOutputProducerSlot < 0 || - (mCompositionType != COMPOSITION_HWC && mFbProducerSlot < 0)) { + (mCompositionType != CompositionType::Hwc && mFbProducerSlot < 0)) { // Last chance bailout if something bad happened earlier. For example, // in a graphics API configuration, if the sink disappears then dequeueBuffer // will fail, the GPU driver won't queue a buffer, but SurfaceFlinger // will soldier on. So we end up here without a buffer. There should // be lots of scary messages in the log just before this. - VDS_LOGE("advanceFrame: no buffer, bailing out"); + VDS_LOGE("%s: no buffer, bailing out", __func__); return NO_MEMORY; } sp fbBuffer = mFbProducerSlot >= 0 ? mProducerBuffers[mFbProducerSlot] : sp(nullptr); sp outBuffer = mProducerBuffers[mOutputProducerSlot]; - VDS_LOGV("advanceFrame: fb=%d(%p) out=%d(%p)", - mFbProducerSlot, fbBuffer.get(), - mOutputProducerSlot, outBuffer.get()); + VDS_LOGV("%s: fb=%d(%p) out=%d(%p)", __func__, mFbProducerSlot, fbBuffer.get(), + mOutputProducerSlot, outBuffer.get()); const auto halDisplayId = HalVirtualDisplayId::tryCast(mDisplayId); LOG_FATAL_IF(!halDisplayId); @@ -245,16 +229,16 @@ void VirtualDisplaySurface::onFrameCommitted() { return; } - VDS_LOGW_IF(mDbgState != DBG_STATE_HWC, - "Unexpected onFrameCommitted() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_IDLE; + VDS_LOGW_IF(mDebugState != DebugState::Hwc, "Unexpected %s in %s state", __func__, + ftl::enum_string(mDebugState).c_str()); + mDebugState = DebugState::Idle; sp retireFence = mHwc.getPresentFence(*halDisplayId); - if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) { + if (mCompositionType == CompositionType::Mixed && mFbProducerSlot >= 0) { // release the scratch buffer back to the pool Mutex::Autolock lock(mMutex); int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot); - VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot); + VDS_LOGV("%s: release scratch sslot=%d", __func__, sslot); addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], retireFence); releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot]); @@ -263,7 +247,7 @@ void VirtualDisplaySurface::onFrameCommitted() { if (mOutputProducerSlot >= 0) { int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot); QueueBufferOutput qbo; - VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot); + VDS_LOGV("%s: queue sink sslot=%d", __func__, sslot); if (mMustRecompose) { status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, QueueBufferInput( @@ -308,8 +292,8 @@ status_t VirtualDisplaySurface::requestBuffer(int pslot, return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf); } - VDS_LOGW_IF(mDbgState != DBG_STATE_GPU, "Unexpected requestBuffer pslot=%d in %s state", pslot, - dbgStateStr()); + VDS_LOGW_IF(mDebugState != DebugState::Gpu, "Unexpected %s pslot=%d in %s state", __func__, + pslot, ftl::enum_string(mDebugState).c_str()); *outBuf = mProducerBuffers[pslot]; return NO_ERROR; @@ -334,8 +318,8 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, if (result < 0) return result; int pslot = mapSource2ProducerSlot(source, *sslot); - VDS_LOGV("dequeueBuffer(%s): sslot=%d pslot=%d result=%d", - dbgSourceStr(source), *sslot, pslot, result); + VDS_LOGV("%s(%s): sslot=%d pslot=%d result=%d", __func__, ftl::enum_string(source).c_str(), + *sslot, pslot, result); uint64_t sourceBit = static_cast(source) << pslot; // reset producer slot reallocation flag @@ -363,10 +347,9 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, mSource[source]->cancelBuffer(*sslot, *fence); return result; } - VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#" PRIx64, - dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(), - mProducerBuffers[pslot]->getPixelFormat(), - mProducerBuffers[pslot]->getUsage()); + VDS_LOGV("%s(%s): buffers[%d]=%p fmt=%d usage=%#" PRIx64, __func__, + ftl::enum_string(source).c_str(), pslot, mProducerBuffers[pslot].get(), + mProducerBuffers[pslot]->getPixelFormat(), mProducerBuffers[pslot]->getUsage()); // propagate reallocation to VDS consumer mProducerSlotNeedReallocation |= 1ULL << pslot; @@ -384,11 +367,11 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, uint outTimestamps); } - VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, - "Unexpected dequeueBuffer() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_GPU; + VDS_LOGW_IF(mDebugState != DebugState::Prepared, "Unexpected %s in %s state", __func__, + ftl::enum_string(mDebugState).c_str()); + mDebugState = DebugState::Gpu; - VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#" PRIx64, w, h, format, usage); + VDS_LOGV("%s %dx%d fmt=%d usage=%#" PRIx64, __func__, w, h, format, usage); status_t result = NO_ERROR; Source source = fbSourceForCompositionType(mCompositionType); @@ -401,7 +384,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, uint // will fail, the GPU driver won't queue a buffer, but SurfaceFlinger // will soldier on. So we end up here without a buffer. There should // be lots of scary messages in the log just before this. - VDS_LOGE("dequeueBuffer: no buffer, bailing out"); + VDS_LOGE("%s: no buffer, bailing out", __func__); return NO_MEMORY; } @@ -417,12 +400,11 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, uint (format != 0 && format != buf->getPixelFormat()) || (w != 0 && w != mSinkBufferWidth) || (h != 0 && h != mSinkBufferHeight)) { - VDS_LOGV("dequeueBuffer: dequeueing new output buffer: " - "want %dx%d fmt=%d use=%#" PRIx64 ", " - "have %dx%d fmt=%d use=%#" PRIx64, - w, h, format, usage, - mSinkBufferWidth, mSinkBufferHeight, - buf->getPixelFormat(), buf->getUsage()); + VDS_LOGV("%s: dequeueing new output buffer: " + "want %dx%d fmt=%d use=%#" PRIx64 ", " + "have %dx%d fmt=%d use=%#" PRIx64, + __func__, w, h, format, usage, mSinkBufferWidth, mSinkBufferHeight, + buf->getPixelFormat(), buf->getUsage()); mOutputFormat = format; mOutputUsage = usage; result = refreshOutputBuffer(); @@ -452,21 +434,16 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, uint return result; } -status_t VirtualDisplaySurface::detachBuffer(int /* slot */) { - VDS_LOGE("detachBuffer is not available for VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::detachBuffer(int) { + UNSUPPORTED(); } -status_t VirtualDisplaySurface::detachNextBuffer( - sp* /* outBuffer */, sp* /* outFence */) { - VDS_LOGE("detachNextBuffer is not available for VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::detachNextBuffer(sp*, sp*) { + UNSUPPORTED(); } -status_t VirtualDisplaySurface::attachBuffer(int* /* outSlot */, - const sp& /* buffer */) { - VDS_LOGE("attachBuffer is not available for VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::attachBuffer(int*, const sp&) { + UNSUPPORTED(); } status_t VirtualDisplaySurface::queueBuffer(int pslot, @@ -475,14 +452,14 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output); } - VDS_LOGW_IF(mDbgState != DBG_STATE_GPU, "Unexpected queueBuffer(pslot=%d) in %s state", pslot, - dbgStateStr()); - mDbgState = DBG_STATE_GPU_DONE; + VDS_LOGW_IF(mDebugState != DebugState::Gpu, "Unexpected %s(pslot=%d) in %s state", __func__, + pslot, ftl::enum_string(mDebugState).c_str()); + mDebugState = DebugState::GpuDone; - VDS_LOGV("queueBuffer pslot=%d", pslot); + VDS_LOGV("%s pslot=%d", __func__, pslot); status_t result; - if (mCompositionType == COMPOSITION_MIXED) { + if (mCompositionType == CompositionType::Mixed) { // Queue the buffer back into the scratch pool QueueBufferOutput scratchQBO; int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot); @@ -498,15 +475,15 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, if (result != NO_ERROR) return result; VDS_LOGW_IF(item.mSlot != sslot, - "queueBuffer: acquired sslot %d from SCRATCH after queueing sslot %d", - item.mSlot, sslot); + "%s: acquired sslot %d from SCRATCH after queueing sslot %d", __func__, + item.mSlot, sslot); mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mSlot); mFbFence = mSlots[item.mSlot].mFence; } else { - LOG_FATAL_IF(mCompositionType != COMPOSITION_GPU, - "Unexpected queueBuffer in state %s for compositionType %s", dbgStateStr(), - dbgCompositionTypeStr(mCompositionType)); + LOG_FATAL_IF(mCompositionType != CompositionType::Gpu, + "Unexpected %s in state %s for composition type %s", __func__, + ftl::enum_string(mDebugState).c_str(), toString(mCompositionType).c_str()); // Extract the GPU release fence for HWC to acquire int64_t timestamp; @@ -533,9 +510,9 @@ status_t VirtualDisplaySurface::cancelBuffer(int pslot, return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence); } - VDS_LOGW_IF(mDbgState != DBG_STATE_GPU, "Unexpected cancelBuffer(pslot=%d) in %s state", pslot, - dbgStateStr()); - VDS_LOGV("cancelBuffer pslot=%d", pslot); + VDS_LOGW_IF(mDebugState != DebugState::Gpu, "Unexpected %s(pslot=%d) in %s state", __func__, + pslot, ftl::enum_string(mDebugState).c_str()); + VDS_LOGV("%s pslot=%d", __func__, pslot); Source source = fbSourceForCompositionType(mCompositionType); return mSource[source]->cancelBuffer( mapProducer2SourceSlot(source, pslot), fence); @@ -573,8 +550,8 @@ status_t VirtualDisplaySurface::disconnect(int api, DisconnectMode mode) { return mSource[SOURCE_SINK]->disconnect(api, mode); } -status_t VirtualDisplaySurface::setSidebandStream(const sp& /*stream*/) { - return INVALID_OPERATION; +status_t VirtualDisplaySurface::setSidebandStream(const sp&) { + UNSUPPORTED(); } void VirtualDisplaySurface::allocateBuffers(uint32_t /* width */, @@ -586,40 +563,32 @@ status_t VirtualDisplaySurface::allowAllocation(bool /* allow */) { return INVALID_OPERATION; } -status_t VirtualDisplaySurface::setGenerationNumber(uint32_t /* generation */) { - ALOGE("setGenerationNumber not supported on VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::setGenerationNumber(uint32_t) { + UNSUPPORTED(); } String8 VirtualDisplaySurface::getConsumerName() const { return String8("VirtualDisplaySurface"); } -status_t VirtualDisplaySurface::setSharedBufferMode(bool /*sharedBufferMode*/) { - ALOGE("setSharedBufferMode not supported on VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::setSharedBufferMode(bool) { + UNSUPPORTED(); } -status_t VirtualDisplaySurface::setAutoRefresh(bool /*autoRefresh*/) { - ALOGE("setAutoRefresh not supported on VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::setAutoRefresh(bool) { + UNSUPPORTED(); } -status_t VirtualDisplaySurface::setDequeueTimeout(nsecs_t /* timeout */) { - ALOGE("setDequeueTimeout not supported on VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::setDequeueTimeout(nsecs_t) { + UNSUPPORTED(); } -status_t VirtualDisplaySurface::getLastQueuedBuffer( - sp* /*outBuffer*/, sp* /*outFence*/, - float[16] /* outTransformMatrix*/) { - ALOGE("getLastQueuedBuffer not supported on VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::getLastQueuedBuffer(sp*, sp*, float[16]) { + UNSUPPORTED(); } -status_t VirtualDisplaySurface::getUniqueId(uint64_t* /*outId*/) const { - ALOGE("getUniqueId not supported on VirtualDisplaySurface"); - return INVALID_OPERATION; +status_t VirtualDisplaySurface::getUniqueId(uint64_t*) const { + UNSUPPORTED(); } status_t VirtualDisplaySurface::getConsumerUsage(uint64_t* outUsage) const { @@ -633,7 +602,7 @@ void VirtualDisplaySurface::updateQueueBufferOutput( } void VirtualDisplaySurface::resetPerFrameState() { - mCompositionType = COMPOSITION_UNKNOWN; + mCompositionType = CompositionType::Unknown; mFbFence = Fence::NO_FENCE; mOutputFence = Fence::NO_FENCE; mOutputProducerSlot = -1; @@ -682,39 +651,16 @@ int VirtualDisplaySurface::mapProducer2SourceSlot(Source source, int pslot) { return mapSource2ProducerSlot(source, pslot); } -VirtualDisplaySurface::Source -VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) { - return type == COMPOSITION_MIXED ? SOURCE_SCRATCH : SOURCE_SINK; +auto VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) -> Source { + return type == CompositionType::Mixed ? SOURCE_SCRATCH : SOURCE_SINK; } -const char* VirtualDisplaySurface::dbgStateStr() const { - switch (mDbgState) { - case DBG_STATE_IDLE: - return "IDLE"; - case DBG_STATE_PREPARED: - return "PREPARED"; - case DBG_STATE_GPU: - return "GPU"; - case DBG_STATE_GPU_DONE: - return "GPU_DONE"; - case DBG_STATE_HWC: - return "HWC"; - default: - return "INVALID"; - } -} - -const char* VirtualDisplaySurface::dbgSourceStr(Source s) { - switch (s) { - case SOURCE_SINK: return "SINK"; - case SOURCE_SCRATCH: return "SCRATCH"; - default: return "INVALID"; - } +std::string VirtualDisplaySurface::toString(CompositionType type) { + using namespace std::literals; + return type == CompositionType::Unknown ? "Unknown"s : Flags(type).string(); } -// --------------------------------------------------------------------------- } // namespace android -// --------------------------------------------------------------------------- // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index bbb6306920..77207134b9 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H -#define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H +#pragma once #include #include @@ -28,9 +27,7 @@ #include "DisplayIdentification.h" -// --------------------------------------------------------------------------- namespace android { -// --------------------------------------------------------------------------- class HWComposer; class IProducerListener; @@ -94,7 +91,13 @@ public: virtual const sp& getClientTargetAcquireFence() const override; private: - enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1}; + enum Source : size_t { + SOURCE_SINK = 0, + SOURCE_SCRATCH = 1, + + ftl_first = SOURCE_SINK, + ftl_last = SOURCE_SCRATCH, + }; virtual ~VirtualDisplaySurface(); @@ -133,6 +136,8 @@ private: // Utility methods // static Source fbSourceForCompositionType(CompositionType); + static std::string toString(CompositionType); + status_t dequeueBuffer(Source, PixelFormat, uint64_t usage, int* sslot, sp*); void updateQueueBufferOutput(QueueBufferOutput&&); void resetPerFrameState(); @@ -197,7 +202,7 @@ private: // Composition type and graphics buffer source for the current frame. // Valid after prepareFrame(), cleared in onFrameCommitted. - CompositionType mCompositionType; + CompositionType mCompositionType = CompositionType::Unknown; // mFbFence is the fence HWC should wait for before reading the framebuffer // target buffer. @@ -219,47 +224,42 @@ private: // +-----------+-------------------+-------------+ // | State | Event || Next State | // +-----------+-------------------+-------------+ - // | IDLE | beginFrame || BEGUN | - // | BEGUN | prepareFrame || PREPARED | - // | PREPARED | dequeueBuffer [1] || GPU | - // | PREPARED | advanceFrame [2] || HWC | - // | GPU | queueBuffer || GPU_DONE | - // | GPU_DONE | advanceFrame || HWC | - // | HWC | onFrameCommitted || IDLE | + // | Idle | beginFrame || Begun | + // | Begun | prepareFrame || Prepared | + // | Prepared | dequeueBuffer [1] || Gpu | + // | Prepared | advanceFrame [2] || Hwc | + // | Gpu | queueBuffer || GpuDone | + // | GpuDone | advanceFrame || Hwc | + // | Hwc | onFrameCommitted || Idle | // +-----------+-------------------++------------+ - // [1] COMPOSITION_GPU and COMPOSITION_MIXED frames. - // [2] COMPOSITION_HWC frames. + // [1] CompositionType::Gpu and CompositionType::Mixed frames. + // [2] CompositionType::Hwc frames. // - enum DbgState { + enum class DebugState { // no buffer dequeued, don't know anything about the next frame - DBG_STATE_IDLE, + Idle, // output buffer dequeued, framebuffer source not yet known - DBG_STATE_BEGUN, + Begun, // output buffer dequeued, framebuffer source known but not provided // to GPU yet. - DBG_STATE_PREPARED, + Prepared, // GPU driver has a buffer dequeued - DBG_STATE_GPU, + Gpu, // GPU driver has queued the buffer, we haven't sent it to HWC yet - DBG_STATE_GPU_DONE, + GpuDone, // HWC has the buffer for this frame - DBG_STATE_HWC, - }; - DbgState mDbgState; - CompositionType mDbgLastCompositionType; + Hwc, - const char* dbgStateStr() const; - static const char* dbgSourceStr(Source s); + ftl_last = Hwc + }; + DebugState mDebugState = DebugState::Idle; + CompositionType mDebugLastCompositionType = CompositionType::Unknown; - bool mMustRecompose; + bool mMustRecompose = false; compositionengine::impl::HwcBufferCache mHwcBufferCache; bool mForceHwcCopy; }; -// --------------------------------------------------------------------------- } // namespace android -// --------------------------------------------------------------------------- - -#endif // ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index c294ff2695..0c4e1120fc 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, int32_t gameMode) + TraceCookieCounter* traceCookieCounter, bool isBuffer, GameMode gameMode) : mToken(frameTimelineInfo.vsyncId), mInputEventId(frameTimelineInfo.inputEventId), mOwnerPid(ownerPid), @@ -778,7 +778,7 @@ 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, int32_t gameMode) { + std::string layerName, std::string debugName, bool isBuffer, GameMode gameMode) { ATRACE_CALL(); if (frameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { return std::make_shared(frameTimelineInfo, ownerPid, ownerUid, layerId, diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index d08344ef6e..36d629077d 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -161,7 +162,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, int32_t gameMode); + TraceCookieCounter* traceCookieCounter, bool isBuffer, GameMode); ~SurfaceFrame() = default; // Returns std::nullopt if the frame hasn't been classified yet. @@ -267,7 +268,7 @@ private: // buffer(animations) bool mIsBuffer; // GameMode from the layer. Used in metrics. - int32_t mGameMode = 0; + GameMode mGameMode = GameMode::Unsupported; }; /* @@ -288,7 +289,7 @@ public: 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, - int32_t gameMode) = 0; + GameMode) = 0; // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be // composited into one display frame. @@ -448,7 +449,7 @@ public: std::shared_ptr createSurfaceFrameForToken( const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, int32_t layerId, std::string layerName, std::string debugName, bool isBuffer, - int32_t gameMode) override; + 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 968a49d526..67f9a92385 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -1411,19 +1412,6 @@ void Layer::miniDumpHeader(std::string& result) { result.append("\n"); } -std::string Layer::frameRateCompatibilityString(Layer::FrameRateCompatibility compatibility) { - switch (compatibility) { - case FrameRateCompatibility::Default: - return "Default"; - case FrameRateCompatibility::ExactOrMultiple: - return "ExactOrMultiple"; - case FrameRateCompatibility::NoVote: - return "NoVote"; - case FrameRateCompatibility::Exact: - return "Exact"; - } -} - void Layer::miniDump(std::string& result, const DisplayDevice& display) const { const auto outputLayer = findOutputLayerForDisplay(&display); if (!outputLayer) { @@ -1462,8 +1450,8 @@ void Layer::miniDump(std::string& result, const DisplayDevice& display) const { const auto frameRate = getFrameRateForLayerTree(); if (frameRate.rate.isValid() || frameRate.type != FrameRateCompatibility::Default) { StringAppendF(&result, "%s %15s %17s", to_string(frameRate.rate).c_str(), - frameRateCompatibilityString(frameRate.type).c_str(), - toString(frameRate.seamlessness).c_str()); + ftl::enum_string(frameRate.type).c_str(), + ftl::enum_string(frameRate.seamlessness).c_str()); } else { result.append(41, ' '); } @@ -1546,11 +1534,10 @@ size_t Layer::getChildrenCount() const { return count; } -void Layer::setGameModeForTree(int parentGameMode) { - int gameMode = parentGameMode; - auto& currentState = getDrawingState(); +void Layer::setGameModeForTree(GameMode gameMode) { + const auto& currentState = getDrawingState(); if (currentState.metadata.has(METADATA_GAME_MODE)) { - gameMode = currentState.metadata.getInt32(METADATA_GAME_MODE, 0); + gameMode = static_cast(currentState.metadata.getInt32(METADATA_GAME_MODE, 0)); } setGameMode(gameMode); for (const sp& child : mCurrentChildren) { @@ -1576,7 +1563,7 @@ ssize_t Layer::removeChild(const sp& layer) { const auto removeResult = mCurrentChildren.remove(layer); updateTreeHasFrameRateVote(); - layer->setGameModeForTree(0); + layer->setGameModeForTree(GameMode::Unsupported); layer->updateTreeHasFrameRateVote(); return removeResult; @@ -2631,12 +2618,11 @@ bool Layer::setDropInputMode(gui::DropInputMode mode) { // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { - return stream << "{rate=" << rate.rate - << " type=" << Layer::frameRateCompatibilityString(rate.type) - << " seamlessness=" << toString(rate.seamlessness) << "}"; + return stream << "{rate=" << rate.rate << " type=" << ftl::enum_string(rate.type) + << " seamlessness=" << ftl::enum_string(rate.seamlessness) << '}'; } -}; // namespace android +} // namespace android #if defined(__gl_h_) #error "don't include gl/gl.h in this file" diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 041b439ac7..47885a4f0c 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -328,7 +328,6 @@ public: static bool isLayerFocusedBasedOnPriority(int32_t priority); static void miniDumpHeader(std::string& result); - static std::string frameRateCompatibilityString(FrameRateCompatibility compatibility); // Provide unique string for each class type in the Layer hierarchy virtual const char* getType() const = 0; @@ -854,12 +853,12 @@ public: */ bool hasInputInfo() const; - // 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(int32_t parentGameMode); - void setGameMode(int32_t gameMode) { mGameMode = gameMode; }; - int32_t getGameMode() const { return mGameMode; } + // Sets the GameMode for the tree rooted at this layer. A layer in the tree inherits this + // GameMode unless it (or an ancestor) has GAME_MODE_METADATA. + void setGameModeForTree(GameMode); + + void setGameMode(GameMode gameMode) { mGameMode = gameMode; } + GameMode getGameMode() const { return mGameMode; } virtual uid_t getOwnerUid() const { return mOwnerUid; } @@ -1110,9 +1109,8 @@ private: // shadow radius is the set shadow radius, otherwise its the parent's shadow radius. float mEffectiveShadowRadius = 0.f; - // Game mode for the layer. Set by WindowManagerShell, game mode is used in - // metrics(SurfaceFlingerStats). - int32_t mGameMode = 0; + // Game mode for the layer. Set by WindowManagerShell and recorded by SurfaceFlingerStats. + GameMode mGameMode = GameMode::Unsupported; // A list of regions on this layer that should have blurs. const std::vector getBlurRegions() const; diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 314526a99d..ae61eeb660 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -28,6 +28,7 @@ #include #include +#include #undef LOG_TAG #define LOG_TAG "LayerInfo" @@ -257,10 +258,10 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateConfigs& ref return {LayerHistory::LayerVoteType::Max, Fps()}; } -const char* LayerInfo::getTraceTag(android::scheduler::LayerHistory::LayerVoteType type) const { +const char* LayerInfo::getTraceTag(LayerHistory::LayerVoteType type) const { if (mTraceTags.count(type) == 0) { - const auto tag = "LFPS " + mName + " " + RefreshRateConfigs::layerVoteTypeString(type); - mTraceTags.emplace(type, tag); + auto tag = "LFPS " + mName + " " + ftl::enum_string(type); + mTraceTags.emplace(type, std::move(tag)); } return mTraceTags.at(type).c_str(); diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 18ed95ec0f..690abda613 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -82,6 +82,8 @@ public: NoVote, // Layer doesn't have any requirements for the refresh rate and // should not be considered when the display refresh rate is determined. + + ftl_last = NoVote }; // Encapsulates the frame rate and compatibility of the layer. This information will be used diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 0d17b0ca94..71d563130e 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -21,23 +21,27 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wextra" -#include "RefreshRateConfigs.h" +#include +#include + #include #include +#include #include -#include -#include + #include "../SurfaceFlingerProperties.h" +#include "RefreshRateConfigs.h" #undef LOG_TAG #define LOG_TAG "RefreshRateConfigs" namespace android::scheduler { namespace { + std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) { return base::StringPrintf("%s (type=%s, weight=%.2f seamlessness=%s) %s", layer.name.c_str(), - RefreshRateConfigs::layerVoteTypeString(layer.vote).c_str(), weight, - toString(layer.seamlessness).c_str(), + ftl::enum_string(layer.vote).c_str(), weight, + ftl::enum_string(layer.seamlessness).c_str(), to_string(layer.desiredRefreshRate).c_str()); } @@ -74,25 +78,6 @@ std::string RefreshRate::toString() const { mode->getWidth(), mode->getHeight(), getModeGroup()); } -std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) { - switch (vote) { - case LayerVoteType::NoVote: - return "NoVote"; - case LayerVoteType::Min: - return "Min"; - case LayerVoteType::Max: - return "Max"; - case LayerVoteType::Heuristic: - return "Heuristic"; - case LayerVoteType::ExplicitDefault: - return "ExplicitDefault"; - case LayerVoteType::ExplicitExactOrMultiple: - return "ExplicitExactOrMultiple"; - case LayerVoteType::ExplicitExact: - return "ExplicitExact"; - } -} - std::string RefreshRateConfigs::Policy::toString() const { return base::StringPrintf("default mode ID: %d, allowGroupSwitching = %d" ", primary range: %s, app request range: %s", @@ -405,7 +390,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( for (const auto& layer : layers) { ALOGV("Calculating score for %s (%s, weight %.2f, desired %.2f) ", layer.name.c_str(), - layerVoteTypeString(layer.vote).c_str(), layer.weight, + ftl::enum_string(layer.vote).c_str(), layer.weight, layer.desiredRefreshRate.getValue()); if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) { continue; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 8a1c2062a6..8c38083561 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -206,6 +206,7 @@ public: ExplicitExact, // Specific refresh rate that was provided by the app with // Exact compatibility + ftl_last = ExplicitExact }; // Captures the layer requirements for a refresh rate. This will be used to determine the @@ -285,9 +286,6 @@ public: // Stores the current modeId the device operates at void setCurrentModeId(DisplayModeId) EXCLUDES(mLock); - // Returns a string that represents the layer vote type - static std::string layerVoteTypeString(LayerVoteType vote); - // Returns a known frame rate that is the closest to frameRate Fps findClosestKnownFrameRate(Fps frameRate) const; diff --git a/services/surfaceflinger/Scheduler/Timer.cpp b/services/surfaceflinger/Scheduler/Timer.cpp index c9c2d84a2a..22c3a709de 100644 --- a/services/surfaceflinger/Scheduler/Timer.cpp +++ b/services/surfaceflinger/Scheduler/Timer.cpp @@ -17,14 +17,18 @@ #undef LOG_TAG #define LOG_TAG "SchedulerTimer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include -#include + +#include +#include + #include #include #include + +#include +#include +#include #include -#include -#include #include "SchedulerUtils.h" #include "Timer.h" @@ -215,26 +219,9 @@ void Timer::setDebugState(DebugState state) { mDebugState = state; } -const char* Timer::strDebugState(DebugState state) const { - switch (state) { - case DebugState::Reset: - return "Reset"; - case DebugState::Running: - return "Running"; - case DebugState::Waiting: - return "Waiting"; - case DebugState::Reading: - return "Reading"; - case DebugState::InCallback: - return "InCallback"; - case DebugState::Terminated: - return "Terminated"; - } -} - void Timer::dump(std::string& result) const { std::lock_guard lock(mMutex); - StringAppendF(&result, "\t\tDebugState: %s\n", strDebugState(mDebugState)); + StringAppendF(&result, "\t\tDebugState: %s\n", ftl::enum_string(mDebugState).c_str()); } } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Timer.h b/services/surfaceflinger/Scheduler/Timer.h index 69ce079437..628d800bc7 100644 --- a/services/surfaceflinger/Scheduler/Timer.h +++ b/services/surfaceflinger/Scheduler/Timer.h @@ -37,11 +37,20 @@ public: void dump(std::string& result) const final; private: - enum class DebugState { Reset, Running, Waiting, Reading, InCallback, Terminated }; + enum class DebugState { + Reset, + Running, + Waiting, + Reading, + InCallback, + Terminated, + + ftl_last = Terminated + }; + void reset(); void cleanup(); void setDebugState(DebugState state) EXCLUDES(mMutex); - const char* strDebugState(DebugState state) const; int mTimerFd = -1; int mEpollFd = -1; diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Seamlessness.h b/services/surfaceflinger/Scheduler/include/scheduler/Seamlessness.h index d7667ec9c6..93bf726731 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/Seamlessness.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/Seamlessness.h @@ -17,7 +17,8 @@ #pragma once #include -#include + +#include namespace android::scheduler { @@ -30,23 +31,14 @@ enum class Seamlessness { // Indicates no preference for seamlessness. For such layers the system will // prefer seamless switches, but also non-seamless switches to the group of the // default config are allowed. - Default -}; + Default, -inline std::string toString(Seamlessness seamlessness) { - switch (seamlessness) { - case Seamlessness::OnlySeamless: - return "OnlySeamless"; - case Seamlessness::SeamedAndSeamless: - return "SeamedAndSeamless"; - case Seamlessness::Default: - return "Default"; - } -} + ftl_last = Default +}; // Used by gtest -inline std::ostream& operator<<(std::ostream& os, Seamlessness val) { - return os << toString(val); +inline std::ostream& operator<<(std::ostream& os, Seamlessness s) { + return os << ftl::enum_string(s); } } // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e497d95306..0a6eb4ff2a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4158,13 +4158,14 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime std::optional dequeueBufferTimestamp; if (what & layer_state_t::eMetadataChanged) { dequeueBufferTimestamp = s.metadata.getInt64(METADATA_DEQUEUE_TIME); - auto gameMode = s.metadata.getInt32(METADATA_GAME_MODE, -1); - if (gameMode != -1) { + + if (const int32_t gameMode = s.metadata.getInt32(METADATA_GAME_MODE, -1); gameMode != -1) { // The transaction will be received on the Task layer and needs to be applied to all // child layers. Child layers that are added at a later point will obtain the game mode // info through addChild(). - layer->setGameModeForTree(gameMode); + layer->setGameModeForTree(static_cast(gameMode)); } + if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded; } if (what & layer_state_t::eColorSpaceAgnosticChanged) { diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index bf2038b277..b1a2bdaa91 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #undef LOG_TAG #define LOG_TAG "TimeStats" #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -28,6 +27,7 @@ #include #include +#include #include "TimeStats.h" #include "timestatsproto/TimeStatsHelper.h" @@ -58,15 +58,15 @@ FrameTimingHistogram histogramToProto(const std::unordered_map return histogramProto; } -SurfaceflingerStatsLayerInfo_GameMode gameModeToProto(int32_t gameMode) { +SurfaceflingerStatsLayerInfo_GameMode gameModeToProto(GameMode gameMode) { switch (gameMode) { - case TimeStatsHelper::GameModeUnsupported: + case GameMode::Unsupported: return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSUPPORTED; - case TimeStatsHelper::GameModeStandard: + case GameMode::Standard: return SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD; - case TimeStatsHelper::GameModePerformance: + case GameMode::Performance: return SurfaceflingerStatsLayerInfo::GAME_MODE_PERFORMANCE; - case TimeStatsHelper::GameModeBattery: + case GameMode::Battery: return SurfaceflingerStatsLayerInfo::GAME_MODE_BATTERY; default: return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSPECIFIED; @@ -454,7 +454,7 @@ static int32_t clampToNearestBucket(Fps fps, size_t bucketWidth) { void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, std::optional renderRate, SetFrameRateVote frameRateVote, - int32_t gameMode) { + GameMode gameMode) { ATRACE_CALL(); ALOGV("[%d]-flushAvailableRecordsToStatsLocked", layerId); @@ -554,7 +554,7 @@ static bool layerNameIsValid(const std::string& layerName) { } bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName, - int32_t gameMode) { + GameMode gameMode) { uint32_t layerRecords = 0; for (const auto& record : mTimeStats.stats) { if (record.second.stats.count({uid, layerName, gameMode}) > 0) { @@ -568,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, int32_t gameMode) { + uid_t uid, nsecs_t postTime, GameMode gameMode) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -718,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, int32_t gameMode) { + SetFrameRateVote frameRateVote, GameMode gameMode) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -744,7 +744,7 @@ void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t pr void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& presentFence, Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote, int32_t gameMode) { + SetFrameRateVote frameRateVote, GameMode gameMode) { if (!mEnabled.load()) return; ATRACE_CALL(); @@ -823,7 +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; + constexpr GameMode kDefaultGameMode = GameMode::Unsupported; const int32_t refreshRateBucket = clampToNearestBucket(info.refreshRate, REFRESH_RATE_BUCKET_WIDTH); diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 23f19b5cfd..77c7973532 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -79,7 +80,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, int32_t gameMode) = 0; + uid_t uid, nsecs_t postTime, 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 { @@ -101,11 +102,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, int32_t gameMode) = 0; + SetFrameRateVote frameRateVote, GameMode) = 0; virtual void setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& presentFence, Fps displayRefreshRate, std::optional renderRate, - SetFrameRateVote frameRateVote, int32_t gameMode) = 0; + SetFrameRateVote frameRateVote, 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 @@ -123,7 +124,7 @@ public: std::optional renderRate; uid_t uid = 0; std::string layerName; - int32_t gameMode = 0; + GameMode gameMode = GameMode::Unsupported; int32_t reasons = 0; nsecs_t displayDeadlineDelta = 0; nsecs_t displayPresentJitter = 0; @@ -194,7 +195,7 @@ class TimeStats : public android::TimeStats { struct LayerRecord { uid_t uid; std::string layerName; - int32_t gameMode = 0; + GameMode gameMode = GameMode::Unsupported; // 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. @@ -247,7 +248,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, int32_t gameMode) override; + nsecs_t postTime, 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; @@ -256,12 +257,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, - SetFrameRateVote frameRateVote, int32_t gameMode) override; + Fps displayRefreshRate, std::optional renderRate, SetFrameRateVote, + GameMode) override; void setPresentFence(int32_t layerId, uint64_t frameNumber, const std::shared_ptr& presentFence, Fps displayRefreshRate, - std::optional renderRate, SetFrameRateVote frameRateVote, - int32_t gameMode) override; + std::optional renderRate, SetFrameRateVote, GameMode) override; void incrementJankyFrames(const JankyFramesInfo& info) override; // Clean up the layer record @@ -282,11 +282,11 @@ private: bool populateLayerAtom(std::string* pulledData); bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord); void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate, - std::optional renderRate, - SetFrameRateVote frameRateVote, int32_t gameMode); + std::optional renderRate, SetFrameRateVote, + GameMode); void flushPowerTimeLocked(); void flushAvailableGlobalRecordsToStatsLocked(); - bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName, int32_t gameMode); + bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName, GameMode); void enable(); void disable(); diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp index ffb2f0921d..69afa2a7a1 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp +++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp @@ -16,9 +16,10 @@ #include "timestatsproto/TimeStatsHelper.h" #include -#include +#include #include +#include #define HISTOGRAM_SIZE 85 @@ -91,51 +92,15 @@ 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()); + ftl::enum_string(frameRateCompatibility).c_str()); + StringAppendF(&result, "seamlessness = %s\n", ftl::enum_string(seamlessness).c_str()); 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); @@ -143,7 +108,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, "gameMode = %s\n", ftl::enum_string(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 2afff8d313..438561cc05 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h +++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h @@ -15,6 +15,7 @@ */ #pragma once +#include #include #include @@ -63,6 +64,8 @@ public: Undefined = 0, Default = 1, ExactOrMultiple = 2, + + ftl_last = ExactOrMultiple } frameRateCompatibility = FrameRateCompatibility::Undefined; // Needs to be in sync with atoms.proto @@ -70,25 +73,13 @@ public: Undefined = 0, ShouldBeSeamless = 1, NotRequired = 2, + + ftl_last = NotRequired } seamlessness = Seamlessness::Undefined; - static std::string toString(FrameRateCompatibility); - static std::string toString(Seamlessness); 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; @@ -96,7 +87,7 @@ public: std::string packageName; int32_t displayRefreshRateBucket = 0; int32_t renderRateBucket = 0; - int32_t gameMode = 0; + GameMode gameMode = GameMode::Unsupported; int32_t totalFrames = 0; int32_t droppedFrames = 0; int32_t lateAcquireFrames = 0; @@ -106,7 +97,6 @@ public: std::unordered_map deltas; std::string toString() const; - std::string toString(int32_t gameMode) const; SFTimeStatsLayerProto toProto() const; }; @@ -137,13 +127,14 @@ public: struct LayerStatsKey { uid_t uid = 0; std::string layerName; - int32_t gameMode = 0; + GameMode gameMode = GameMode::Unsupported; struct Hasher { size_t operator()(const LayerStatsKey& key) const { size_t uidHash = std::hash{}(key.uid); size_t layerNameHash = std::hash{}(key.layerName); - size_t gameModeHash = std::hash{}(key.gameMode); + using T = std::underlying_type_t; + size_t gameModeHash = std::hash{}(static_cast(key.gameMode)); return HashCombine(uidHash, HashCombine(layerNameHash, gameModeHash)); } }; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 8d2c078305..c7c6b06386 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -370,7 +370,7 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1); EXPECT_CALL(*test->mDisplaySurface, - prepareFrame(compositionengine::DisplaySurface::COMPOSITION_HWC)) + prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc)) .Times(1); } @@ -384,7 +384,7 @@ struct BaseDisplayVariant { static void setupRECompositionCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mDisplaySurface, - prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GPU)) + prepareFrame(compositionengine::DisplaySurface::CompositionType::Gpu)) .Times(1); EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence()) .WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence)); diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index 9fbaeced7b..397c6193bf 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -169,13 +169,14 @@ public: static const std::string sLayerNameOne = "layer1"; static const std::string sLayerNameTwo = "layer2"; -static constexpr const uid_t sUidOne = 0; -static constexpr pid_t sPidOne = 10; -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; + +constexpr const uid_t sUidOne = 0; +constexpr pid_t sPidOne = 10; +constexpr pid_t sPidTwo = 20; +constexpr int32_t sInputEventId = 5; +constexpr int32_t sLayerIdOne = 1; +constexpr int32_t sLayerIdTwo = 2; +constexpr GameMode sGameMode = GameMode::Unsupported; TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); diff --git a/services/surfaceflinger/tests/unittests/GameModeTest.cpp b/services/surfaceflinger/tests/unittests/GameModeTest.cpp index d6459429fb..981ca1d227 100644 --- a/services/surfaceflinger/tests/unittests/GameModeTest.cpp +++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp @@ -91,8 +91,8 @@ public: } // Mocks the behavior of applying a transaction from WMShell - void setGameModeMetadata(sp layer, int gameMode) { - mLayerMetadata.setInt32(METADATA_GAME_MODE, gameMode); + void setGameModeMetadata(sp layer, GameMode gameMode) { + mLayerMetadata.setInt32(METADATA_GAME_MODE, static_cast(gameMode)); layer->setMetadata(mLayerMetadata); layer->setGameModeForTree(gameMode); } @@ -109,51 +109,52 @@ TEST_F(GameModeTest, SetGameModeSetsForAllCurrentChildren) { sp childLayer2 = createBufferStateLayer(); rootLayer->addChild(childLayer1); rootLayer->addChild(childLayer2); - rootLayer->setGameModeForTree(/*gameMode*/ 2); + rootLayer->setGameModeForTree(GameMode::Performance); - EXPECT_EQ(rootLayer->getGameMode(), 2); - EXPECT_EQ(childLayer1->getGameMode(), 2); - EXPECT_EQ(childLayer2->getGameMode(), 2); + EXPECT_EQ(rootLayer->getGameMode(), GameMode::Performance); + EXPECT_EQ(childLayer1->getGameMode(), GameMode::Performance); + EXPECT_EQ(childLayer2->getGameMode(), GameMode::Performance); } TEST_F(GameModeTest, AddChildAppliesGameModeFromParent) { sp rootLayer = createBufferStateLayer(); sp childLayer = createBufferStateLayer(); - rootLayer->setGameModeForTree(/*gameMode*/ 2); + rootLayer->setGameModeForTree(GameMode::Performance); rootLayer->addChild(childLayer); - EXPECT_EQ(rootLayer->getGameMode(), 2); - EXPECT_EQ(childLayer->getGameMode(), 2); + EXPECT_EQ(rootLayer->getGameMode(), GameMode::Performance); + EXPECT_EQ(childLayer->getGameMode(), GameMode::Performance); } TEST_F(GameModeTest, RemoveChildResetsGameMode) { sp rootLayer = createBufferStateLayer(); sp childLayer = createBufferStateLayer(); - rootLayer->setGameModeForTree(/*gameMode*/ 2); + rootLayer->setGameModeForTree(GameMode::Performance); rootLayer->addChild(childLayer); - EXPECT_EQ(rootLayer->getGameMode(), 2); - EXPECT_EQ(childLayer->getGameMode(), 2); + EXPECT_EQ(rootLayer->getGameMode(), GameMode::Performance); + EXPECT_EQ(childLayer->getGameMode(), GameMode::Performance); rootLayer->removeChild(childLayer); - EXPECT_EQ(childLayer->getGameMode(), 0); + EXPECT_EQ(childLayer->getGameMode(), GameMode::Unsupported); } TEST_F(GameModeTest, ReparentingDoesNotOverrideMetadata) { sp rootLayer = createBufferStateLayer(); sp childLayer1 = createBufferStateLayer(); sp childLayer2 = createBufferStateLayer(); - rootLayer->setGameModeForTree(/*gameMode*/ 1); + rootLayer->setGameModeForTree(GameMode::Standard); rootLayer->addChild(childLayer1); - setGameModeMetadata(childLayer2, /*gameMode*/ 2); + setGameModeMetadata(childLayer2, GameMode::Performance); rootLayer->addChild(childLayer2); - EXPECT_EQ(rootLayer->getGameMode(), 1); - EXPECT_EQ(childLayer1->getGameMode(), 1); - EXPECT_EQ(childLayer2->getGameMode(), 2); + EXPECT_EQ(rootLayer->getGameMode(), GameMode::Standard); + EXPECT_EQ(childLayer1->getGameMode(), GameMode::Standard); + EXPECT_EQ(childLayer2->getGameMode(), GameMode::Performance); rootLayer->removeChild(childLayer2); - EXPECT_EQ(childLayer2->getGameMode(), 2); + EXPECT_EQ(childLayer2->getGameMode(), GameMode::Performance); } -} // namespace android \ No newline at end of file + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index fc84d48b46..98746bcd21 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -21,10 +21,9 @@ #undef LOG_TAG #define LOG_TAG "SchedulerUnittests" +#include #include #include -#include - #include #include "DisplayHardware/HWC2.h" @@ -1975,7 +1974,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_deviceWithCloseRefreshRates) { layers[0].vote = vote; EXPECT_EQ(fps.getIntValue(), refreshRateConfigs->getBestRefreshRate(layers, {}).getFps().getIntValue()) - << "Failed for " << RefreshRateConfigs::layerVoteTypeString(vote); + << "Failed for " << ftl::enum_string(vote); }; for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index 1487a962f9..0ef8456739 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -70,9 +70,9 @@ using SurfaceflingerStatsLayerInfoWrapper = #define NUM_LAYERS 1 #define NUM_LAYERS_INVALID "INVALID" -const constexpr Fps kRefreshRate0 = 61_Hz; -const constexpr Fps kRenderRate0 = 31_Hz; -static constexpr int32_t kGameMode = TimeStatsHelper::GameModeUnsupported; +constexpr Fps kRefreshRate0 = 61_Hz; +constexpr Fps kRenderRate0 = 31_Hz; +constexpr GameMode kGameMode = GameMode::Unsupported; enum InputCommand : int32_t { ENABLE = 0, @@ -145,14 +145,14 @@ public: std::string inputCommand(InputCommand cmd, bool useProto); void setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts, - TimeStats::SetFrameRateVote frameRateVote, int32_t gameMode); + TimeStats::SetFrameRateVote, 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 = {}, - int32_t gameMode = kGameMode) { + GameMode gameMode = kGameMode) { for (size_t i = 0; i < N; i++, ts += 1000000) { setTimeStamp(sequence[i], id, frameNumber, ts, frameRateVote, gameMode); } @@ -203,7 +203,7 @@ static std::string genLayerName(int32_t layerId) { } void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts, - TimeStats::SetFrameRateVote frameRateVote, int32_t gameMode) { + TimeStats::SetFrameRateVote frameRateVote, GameMode gameMode) { switch (type) { case TimeStamp::POST: ASSERT_NO_FATAL_FAILURE(mTimeStats->setPostTime(id, frameNumber, genLayerName(id), @@ -1168,8 +1168,7 @@ 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, {}, - TimeStatsHelper::GameModeStandard); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000, {}, GameMode::Standard); for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) { mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire); } @@ -1182,42 +1181,39 @@ TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) { TimeStats::SetFrameRateVote::FrameRateCompatibility::ExactOrMultiple, .seamlessness = TimeStats::SetFrameRateVote::Seamlessness::NotRequired, }; - insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate60, - TimeStatsHelper::GameModeStandard); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate60, GameMode::Standard); - 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), - TimeStatsHelper::GameModeStandard, JankType::DisplayHAL, + GameMode::Standard, 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::AppDeadlineMissed, DISPLAY_DEADLINE_DELTA, - DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS}); + GameMode::Standard, JankType::SurfaceFlingerGpuDeadlineMissed, + 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}); + GameMode::Standard, 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::PredictionError, + GameMode::Standard, JankType::AppDeadlineMissed, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, - APP_DEADLINE_DELTA_2MS}); + APP_DEADLINE_DELTA_3MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - TimeStatsHelper::GameModeStandard, - JankType::AppDeadlineMissed | JankType::BufferStuffing, - DISPLAY_DEADLINE_DELTA, APP_DEADLINE_DELTA_2MS, + GameMode::Standard, JankType::SurfaceFlingerScheduling, + DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_2MS}); mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), - TimeStatsHelper::GameModeStandard, JankType::None, + GameMode::Standard, JankType::PredictionError, DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER, - APP_DEADLINE_DELTA_3MS}); + APP_DEADLINE_DELTA_2MS}); + mTimeStats->incrementJankyFrames( + {kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0), GameMode::Standard, + 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), + GameMode::Standard, 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)); @@ -1293,22 +1289,18 @@ TEST_F(TimeStatsTest, layerStatsCallback_multipleGameModes) { 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); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000, {}, GameMode::Standard); 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); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, {}, GameMode::Standard); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 3000000, {}, GameMode::Performance); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 4000000, {}, GameMode::Battery); + insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 5, 4000000, {}, GameMode::Battery); std::string pulledData; EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData)); diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h index 5aebd2f20e..0a69b562ab 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h @@ -41,19 +41,21 @@ 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_METHOD6(setPostTime, void(int32_t, uint64_t, const std::string&, uid_t, nsecs_t, int32_t)); + MOCK_METHOD(void, setPostTime, + (int32_t, uint64_t, const std::string&, uid_t, nsecs_t, GameMode), (override)); 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_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, int32_t)); + MOCK_METHOD(void, setPresentTime, + (int32_t, uint64_t, nsecs_t, Fps, std::optional, SetFrameRateVote, GameMode), + (override)); + MOCK_METHOD(void, setPresentFence, + (int32_t, uint64_t, const std::shared_ptr&, Fps, std::optional, + SetFrameRateVote, GameMode), + (override)); 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 1303d91354c4deb4c56a2beeafee53684b92c821 Mon Sep 17 00:00:00 2001 From: Nathaniel Nifong Date: Wed, 6 Oct 2021 09:41:24 -0400 Subject: Pass fps data to flattener Use this extra data in determining if a layer should be considered inactive for flattening. The effect is that sub 1 fps layers are cached immediately upon updating. Test: Unit tests added, and confirmation of the intended effect on R6 during camera recording using dumpsys surfaceflinger (expected all CameraLauncher layers to be device composited) Bug: b/192271493 Change-Id: I06f2dd0b3256da5699ffca7347285dc8cf52713c --- .../compositionengine/LayerFECompositionState.h | 3 + .../compositionengine/impl/planner/Flattener.h | 7 ++ .../compositionengine/impl/planner/LayerState.h | 1 + .../CompositionEngine/src/planner/Flattener.cpp | 13 +- .../tests/planner/FlattenerTest.cpp | 16 +++ services/surfaceflinger/Layer.cpp | 8 +- services/surfaceflinger/Scheduler/LayerHistory.cpp | 133 ++++++++++++++------- services/surfaceflinger/Scheduler/LayerHistory.h | 42 ++++--- services/surfaceflinger/Scheduler/LayerInfo.cpp | 12 +- services/surfaceflinger/Scheduler/LayerInfo.h | 3 + services/surfaceflinger/Scheduler/Scheduler.h | 5 + services/surfaceflinger/SurfaceFlinger.h | 5 + .../tests/unittests/LayerHistoryTest.cpp | 70 ++++++++--- .../tests/unittests/TestableScheduler.h | 9 +- 14 files changed, 243 insertions(+), 84 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index a000661c79..36594ea83c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -200,6 +200,9 @@ struct LayerFECompositionState { // The output-independent frame for the cursor Rect cursorFrame; + // framerate of the layer as measured by LayerHistory + float fps; + virtual ~LayerFECompositionState(); // Debugging diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h index cff652755d..c13204115d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h @@ -87,6 +87,13 @@ public: const bool mEnableHolePunch; }; + // Constants not yet backed by a sysprop + // CachedSets that contain no more than this many layers may be considered inactive on the basis + // of FPS. + static constexpr int kNumLayersFpsConsideration = 1; + // Frames/Second threshold below which these CachedSets may be considered inactive. + static constexpr float kFpsActiveThreshold = 1.f; + Flattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables); void setDisplaySize(ui::Size size) { diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h index 523752719d..7397c19837 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h @@ -245,6 +245,7 @@ public: bool isProtected() const { return getOutputLayer()->getLayerFE().getCompositionState()->hasProtectedContent; } + float getFps() const { return getOutputLayer()->getLayerFE().getCompositionState()->fps; } void dump(std::string& result) const; std::optional compare(const LayerState& other) const; diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp index 2272099c77..8a476c5ec6 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp @@ -409,10 +409,19 @@ std::vector Flattener::findCandidateRuns(time_point now) const { bool runHasFirstLayer = false; for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) { - const bool layerIsInactive = - now - currentSet->getLastUpdate() > mTunables.mActiveLayerTimeout; + bool layerIsInactive = now - currentSet->getLastUpdate() > mTunables.mActiveLayerTimeout; const bool layerHasBlur = currentSet->hasBlurBehind(); + // Layers should also be considered inactive whenever their framerate is lower than 1fps. + if (!layerIsInactive && currentSet->getLayerCount() == kNumLayersFpsConsideration) { + auto layerFps = currentSet->getFirstLayer().getState()->getFps(); + if (layerFps > 0 && layerFps <= kFpsActiveThreshold) { + ATRACE_FORMAT("layer is considered inactive due to low FPS [%s] %f", + currentSet->getFirstLayer().getName().c_str(), layerFps); + layerIsInactive = true; + } + } + if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) && !currentSet->hasUnsupportedDataspace()) { if (isPartOfRun) { diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp index 9b0a75fd47..6fbcc759c2 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp @@ -224,6 +224,22 @@ TEST_F(FlattenerTest, flattenLayers_ActiveLayersAreNotFlattened) { mFlattener->renderCachedSets(mOutputState, std::nullopt); } +TEST_F(FlattenerTest, flattenLayers_ActiveLayersWithLowFpsAreFlattened) { + mTestLayers[0]->layerFECompositionState.fps = Flattener::kFpsActiveThreshold / 2; + mTestLayers[1]->layerFECompositionState.fps = Flattener::kFpsActiveThreshold; + + auto& layerState1 = mTestLayers[0]->layerState; + auto& layerState2 = mTestLayers[1]->layerState; + + const std::vector layers = { + layerState1.get(), + layerState2.get(), + }; + + initializeFlattener(layers); + expectAllLayersFlattened(layers); +} + TEST_F(FlattenerTest, flattenLayers_basicFlatten) { auto& layerState1 = mTestLayers[0]->layerState; auto& layerState2 = mTestLayers[1]->layerState; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index dfb99cc7ab..4606746d4b 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -418,6 +418,8 @@ void Layer::prepareBasicGeometryCompositionState() { compositionState->blendMode = static_cast(blendMode); compositionState->alpha = alpha; + compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius; + compositionState->blurRegions = drawingState.blurRegions; compositionState->stretchEffect = getStretchEffect(); } @@ -482,6 +484,11 @@ void Layer::preparePerFrameCompositionState() { // If there are no visible region changes, we still need to update blur parameters. compositionState->blurRegions = drawingState.blurRegions; compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius; + + // Layer framerate is used in caching decisions. + // Retrieve it from the scheduler which maintains an instance of LayerHistory, and store it in + // LayerFECompositionState where it would be visible to Flattener. + compositionState->fps = mFlinger->getLayerFramerate(systemTime(), getSequence()); } void Layer::prepareCursorCompositionState() { @@ -932,7 +939,6 @@ bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) { setTransactionFlags(eTransactionNeeded); return true; } - bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix, bool allowNonRectPreservingTransforms) { ui::Transform t; diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 84e3548b6e..74a2ca786c 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -84,42 +84,38 @@ LayerHistory::~LayerHistory() = default; void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) { std::lock_guard lock(mLock); - for (const auto& info : mLayerInfos) { - LOG_ALWAYS_FATAL_IF(info.first == layer, "%s already registered", layer->getName().c_str()); - } + LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first != + LayerHistory::layerStatus::NotFound, + "%s already registered", layer->getName().c_str()); auto info = std::make_unique(layer->getName(), layer->getOwnerUid(), type); - mLayerInfos.emplace_back(layer, std::move(info)); + + // The layer can be placed on either map, it is assumed that partitionLayers() will be called + // to correct them. + mInactiveLayerInfos.insert({layer->getSequence(), std::make_pair(layer, std::move(info))}); } void LayerHistory::deregisterLayer(Layer* layer) { std::lock_guard lock(mLock); - - const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(), - [layer](const auto& pair) { return pair.first == layer; }); - LOG_ALWAYS_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer); - - const size_t i = static_cast(it - mLayerInfos.begin()); - if (i < mActiveLayersEnd) { - mActiveLayersEnd--; + if (!mActiveLayerInfos.erase(layer->getSequence())) { + if (!mInactiveLayerInfos.erase(layer->getSequence())) { + LOG_ALWAYS_FATAL("%s: unknown layer %p", __FUNCTION__, layer); + } } - const size_t last = mLayerInfos.size() - 1; - std::swap(mLayerInfos[i], mLayerInfos[last]); - mLayerInfos.erase(mLayerInfos.begin() + static_cast(last)); } void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType) { std::lock_guard lock(mLock); + auto id = layer->getSequence(); - const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(), - [layer](const auto& pair) { return pair.first == layer; }); - if (it == mLayerInfos.end()) { + auto [found, layerPair] = findLayer(id); + if (found == LayerHistory::layerStatus::NotFound) { // Offscreen layer ALOGV("LayerHistory::record: %s not registered", layer->getName().c_str()); return; } - const auto& info = it->second; + const auto& info = layerPair->second; const auto layerProps = LayerInfo::LayerProps{ .visible = layer->isVisible(), .bounds = layer->getBounds(), @@ -131,9 +127,10 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now, info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps); // Activate layer if inactive. - if (const auto end = activeLayers().end(); it >= end) { - std::iter_swap(it, end); - mActiveLayersEnd++; + if (found == LayerHistory::layerStatus::LayerInInactiveMap) { + mActiveLayerInfos.insert( + {id, std::make_pair(layerPair->first, std::move(layerPair->second))}); + mInactiveLayerInfos.erase(id); } } @@ -145,7 +142,8 @@ LayerHistory::Summary LayerHistory::summarize(const RefreshRateConfigs& refreshR partitionLayers(now); - for (const auto& [layer, info] : activeLayers()) { + for (const auto& [key, value] : mActiveLayerInfos) { + auto& info = value.second; const auto frameRateSelectionPriority = info->getFrameRateSelectionPriority(); const auto layerFocused = Layer::isLayerFocusedBasedOnPriority(frameRateSelectionPriority); ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority, @@ -179,12 +177,29 @@ LayerHistory::Summary LayerHistory::summarize(const RefreshRateConfigs& refreshR void LayerHistory::partitionLayers(nsecs_t now) { const nsecs_t threshold = getActiveLayerThreshold(now); - // Collect expired and inactive layers after active layers. - size_t i = 0; - while (i < mActiveLayersEnd) { - auto& [layerUnsafe, info] = mLayerInfos[i]; + // iterate over inactive map + LayerInfos::iterator it = mInactiveLayerInfos.begin(); + while (it != mInactiveLayerInfos.end()) { + auto& [layerUnsafe, info] = it->second; + if (isLayerActive(*info, threshold)) { + // move this to the active map + + mActiveLayerInfos.insert({it->first, std::move(it->second)}); + it = mInactiveLayerInfos.erase(it); + } else { + if (CC_UNLIKELY(mTraceEnabled)) { + trace(*info, LayerHistory::LayerVoteType::NoVote, 0); + } + info->onLayerInactive(now); + it++; + } + } + + // iterate over active map + it = mActiveLayerInfos.begin(); + while (it != mActiveLayerInfos.end()) { + auto& [layerUnsafe, info] = it->second; if (isLayerActive(*info, threshold)) { - i++; // Set layer vote if set const auto frameRate = info->getSetFrameRateVote(); const auto voteType = [&]() { @@ -206,30 +221,68 @@ void LayerHistory::partitionLayers(nsecs_t now) { } else { info->resetLayerVote(); } - continue; - } - if (CC_UNLIKELY(mTraceEnabled)) { - trace(*info, LayerHistory::LayerVoteType::NoVote, 0); + it++; + } else { + if (CC_UNLIKELY(mTraceEnabled)) { + trace(*info, LayerHistory::LayerVoteType::NoVote, 0); + } + info->onLayerInactive(now); + // move this to the inactive map + mInactiveLayerInfos.insert({it->first, std::move(it->second)}); + it = mActiveLayerInfos.erase(it); } - - info->onLayerInactive(now); - std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]); } } void LayerHistory::clear() { std::lock_guard lock(mLock); - - for (const auto& [layer, info] : activeLayers()) { - info->clearHistory(systemTime()); + for (const auto& [key, value] : mActiveLayerInfos) { + value.second->clearHistory(systemTime()); } } std::string LayerHistory::dump() const { std::lock_guard lock(mLock); - return base::StringPrintf("LayerHistory{size=%zu, active=%zu}", mLayerInfos.size(), - mActiveLayersEnd); + return base::StringPrintf("LayerHistory{size=%zu, active=%zu}", + mActiveLayerInfos.size() + mInactiveLayerInfos.size(), + mActiveLayerInfos.size()); +} + +float LayerHistory::getLayerFramerate(nsecs_t now, int32_t id) const { + std::lock_guard lock(mLock); + auto [found, layerPair] = findLayer(id); + if (found != LayerHistory::layerStatus::NotFound) { + return layerPair->second->getFps(now).getValue(); + } + return 0.f; +} + +std::pair LayerHistory::findLayer(int32_t id) { + // the layer could be in either the active or inactive map, try both + auto it = mActiveLayerInfos.find(id); + if (it != mActiveLayerInfos.end()) { + return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second)); + } + it = mInactiveLayerInfos.find(id); + if (it != mInactiveLayerInfos.end()) { + return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second)); + } + return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr); +} + +std::pair LayerHistory::findLayer( + int32_t id) const { + // the layer could be in either the active or inactive map, try both + auto it = mActiveLayerInfos.find(id); + if (it != mActiveLayerInfos.end()) { + return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second)); + } + it = mInactiveLayerInfos.find(id); + if (it != mInactiveLayerInfos.end()) { + return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second)); + } + return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr); } } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 8d56951363..cc55700503 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -72,34 +73,43 @@ public: void deregisterLayer(Layer*); std::string dump() const; + // return the frames per second of the layer with the given sequence id. + float getLayerFramerate(nsecs_t now, int32_t id) const; + private: friend class LayerHistoryTest; friend class TestableScheduler; using LayerPair = std::pair>; - using LayerInfos = std::vector; + // keyed by id as returned from Layer::getSequence() + using LayerInfos = std::unordered_map; - struct ActiveLayers { - LayerInfos& infos; - const size_t index; + // Iterates over layers maps moving all active layers to mActiveLayerInfos and all inactive + // layers to mInactiveLayerInfos. + // worst case time complexity is O(2 * inactive + active) + void partitionLayers(nsecs_t now) REQUIRES(mLock); - auto begin() { return infos.begin(); } - auto end() { return begin() + static_cast(index); } + enum class layerStatus { + NotFound, + LayerInActiveMap, + LayerInInactiveMap, }; - ActiveLayers activeLayers() REQUIRES(mLock) { return {mLayerInfos, mActiveLayersEnd}; } - - // Iterates over layers in a single pass, swapping pairs such that active layers precede - // inactive layers, and inactive layers precede expired layers. Removes expired layers by - // truncating after inactive layers. - void partitionLayers(nsecs_t now) REQUIRES(mLock); + // looks up a layer by sequence id in both layerInfo maps. + // The first element indicates if and where the item was found + std::pair findLayer(int32_t id) REQUIRES(mLock); + std::pair findLayer(int32_t id) const + REQUIRES(mLock); mutable std::mutex mLock; - // Partitioned such that active layers precede inactive layers. For fast lookup, the few active - // layers are at the front, and weak pointers are stored in contiguous memory to hit the cache. - LayerInfos mLayerInfos GUARDED_BY(mLock); - size_t mActiveLayersEnd GUARDED_BY(mLock) = 0; + // Partitioned into two maps to facility two kinds of retrieval: + // 1. retrieval of a layer by id (attempt lookup in both maps) + // 2. retrieval of all active layers (iterate that map) + // The partitioning is allowed to become out of date but calling partitionLayers refreshes the + // validity of each map. + LayerInfos mActiveLayerInfos GUARDED_BY(mLock); + LayerInfos mInactiveLayerInfos GUARDED_BY(mLock); uint32_t mDisplayArea = 0; diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index ae61eeb660..943615c45c 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -75,12 +75,16 @@ bool LayerInfo::isFrameTimeValid(const FrameTimeData& frameTime) const { } bool LayerInfo::isFrequent(nsecs_t now) const { + using fps_approx_ops::operator>=; // If we know nothing about this layer we consider it as frequent as it might be the start // of an animation. if (mFrameTimes.size() < kFrequentLayerWindowSize) { return true; } + return getFps(now) >= kMinFpsForFrequentLayer; +} +Fps LayerInfo::getFps(nsecs_t now) const { // Find the first active frame auto it = mFrameTimes.begin(); for (; it != mFrameTimes.end(); ++it) { @@ -91,14 +95,12 @@ bool LayerInfo::isFrequent(nsecs_t now) const { const auto numFrames = std::distance(it, mFrameTimes.end()); if (numFrames < kFrequentLayerWindowSize) { - return false; + return Fps(); } - using fps_approx_ops::operator>=; - // Layer is considered frequent if the average frame rate is higher than the threshold const auto totalTime = mFrameTimes.back().queueTime - it->queueTime; - return Fps::fromPeriodNsecs(totalTime / (numFrames - 1)) >= kMinFpsForFrequentLayer; + return Fps::fromPeriodNsecs(totalTime / (numFrames - 1)); } bool LayerInfo::isAnimating(nsecs_t now) const { @@ -236,7 +238,7 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateConfigs& ref if (!isFrequent(now)) { ALOGV("%s is infrequent", mName.c_str()); mLastRefreshRate.animatingOrInfrequent = true; - // Infrequent layers vote for minimal refresh rate for + // Infrequent layers vote for mininal refresh rate for // battery saving purposes and also to prevent b/135718869. return {LayerHistory::LayerVoteType::Min, Fps()}; } diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 690abda613..2d88a4fb9d 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -178,6 +178,9 @@ public: // Returns a C string for tracing a vote const char* getTraceTag(LayerHistory::LayerVoteType type) const; + // Return the framerate of this layer. + Fps getFps(nsecs_t now) const; + void onLayerInactive(nsecs_t now) { // Mark mFrameTimeValidSince to now to ignore all previous frame times. // We are not deleting the old frame to keep track of whether we should treat the first diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index e127ff7371..818f1edb41 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -233,6 +233,11 @@ public: return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); } + // Returns the framerate of the layer with the given sequence ID + float getLayerFramerate(nsecs_t now, int32_t id) const { + return mLayerHistory.getLayerFramerate(now, id); + } + private: friend class TestableScheduler; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 9794639070..d286a8c548 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1351,6 +1351,11 @@ private: const sp mWindowInfosListenerInvoker; std::unique_ptr mFlagManager; + + // returns the framerate of the layer with the given sequence ID + float getLayerFramerate(nsecs_t now, int32_t id) const { + return mScheduler->getLayerFramerate(now, id); + } }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 00687ad4b6..cdb2240b40 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -63,33 +63,42 @@ protected: const LayerHistory& history() const { return mScheduler->mutableLayerHistory(); } LayerHistory::Summary summarizeLayerHistory(nsecs_t now) { - return history().summarize(*mScheduler->refreshRateConfigs(), now); + // LayerHistory::summarize makes no guarantee of the order of the elements in the summary + // however, for testing only, a stable order is required, therefore we sort the list here. + // Any tests requiring ordered results must create layers with names. + auto summary = history().summarize(*mScheduler->refreshRateConfigs(), now); + std::sort(summary.begin(), summary.end(), + [](const RefreshRateConfigs::LayerRequirement& a, + const RefreshRateConfigs::LayerRequirement& b) -> bool { + return a.name < b.name; + }); + return summary; } size_t layerCount() const { return mScheduler->layerHistorySize(); } - size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; } + size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { + return history().mActiveLayerInfos.size(); + } auto frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { - const auto& infos = history().mLayerInfos; - return std::count_if(infos.begin(), - infos.begin() + static_cast(history().mActiveLayersEnd), - [now](const auto& pair) { return pair.second->isFrequent(now); }); + const auto& infos = history().mActiveLayerInfos; + return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) { + return pair.second.second->isFrequent(now); + }); } auto animatingLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { - const auto& infos = history().mLayerInfos; - return std::count_if(infos.begin(), - infos.begin() + static_cast(history().mActiveLayersEnd), - [now](const auto& pair) { return pair.second->isAnimating(now); }); + const auto& infos = history().mActiveLayerInfos; + return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) { + return pair.second.second->isAnimating(now); + }); } void setDefaultLayerVote(Layer* layer, LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS { - for (auto& [layerUnsafe, info] : history().mLayerInfos) { - if (layerUnsafe == layer) { - info->setDefaultLayerVote(vote); - return; - } + auto [found, layerPair] = history().findLayer(layer->getSequence()); + if (found != LayerHistory::layerStatus::NotFound) { + layerPair->second->setDefaultLayerVote(vote); } } @@ -144,6 +153,8 @@ TEST_F(LayerHistoryTest, oneLayer) { EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + // history().registerLayer(layer, LayerHistory::LayerVoteType::Max); + EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -368,9 +379,9 @@ TEST_F(LayerHistoryTest, oneLayerExplicitExactVote) { } TEST_F(LayerHistoryTest, multipleLayers) { - auto layer1 = createLayer(); - auto layer2 = createLayer(); - auto layer3 = createLayer(); + auto layer1 = createLayer("A"); + auto layer2 = createLayer("B"); + auto layer3 = createLayer("C"); EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); @@ -654,6 +665,29 @@ TEST_F(LayerHistoryTest, infrequentAnimatingLayer) { EXPECT_EQ(1, animatingLayerCount(time)); } +TEST_F(LayerHistoryTest, getFramerate) { + auto layer = createLayer(); + + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + + nsecs_t time = systemTime(); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // layer is active but infrequent. + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + } + + float expectedFramerate = 1e9f / MAX_FREQUENT_LAYER_PERIOD_NS.count(); + EXPECT_FLOAT_EQ(expectedFramerate, history().getLayerFramerate(time, layer->getSequence())); +} + TEST_F(LayerHistoryTest, heuristicLayer60Hz) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index dabd2d2cc2..364d8f1411 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -67,11 +67,16 @@ public: auto& mutableLayerHistory() { return mLayerHistory; } - size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mLayerInfos.size(); } - size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mActiveLayersEnd; } + size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS { + return mLayerHistory.mActiveLayerInfos.size() + mLayerHistory.mInactiveLayerInfos.size(); + } auto refreshRateConfigs() { return holdRefreshRateConfigs(); } + size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS { + return mLayerHistory.mActiveLayerInfos.size(); + } + void replaceTouchTimer(int64_t millis) { if (mTouchTimer) { mTouchTimer.reset(); -- cgit v1.2.3-59-g8ed1b From ed511efbdfac3408cb3ae237016f095fd64cebec Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Mon, 11 Oct 2021 15:09:51 -0700 Subject: Add frame timeline method to ASurfaceControl NDK. Bug: 198192003 Test: atest ASurfaceControlTest perfetto trace Change-Id: I04310bd9190cfc227ff5ba892c7187d3b8a20463 --- include/android/surface_control.h | 9 +++++++++ libs/gui/FrameTimelineInfo.cpp | 5 +++++ libs/gui/Surface.cpp | 3 ++- libs/gui/include/gui/FrameTimelineInfo.h | 3 +++ libs/nativewindow/include/system/window.h | 9 +++++---- services/surfaceflinger/FrameTimeline/FrameTimeline.cpp | 3 ++- services/surfaceflinger/Layer.cpp | 2 ++ 7 files changed, 28 insertions(+), 6 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/include/android/surface_control.h b/include/android/surface_control.h index 059bc41f9a..3a131045e8 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -595,6 +595,15 @@ void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* transaction, bool enableBackPressure) __INTRODUCED_IN(31); +/** + * Sets the frame timeline to use. + * + * \param vsyncId The vsync ID received from AChoreographer, setting the frame's present target to + * the corresponding expected present time and deadline from the frame to be rendered. + */ +void ASurfaceTransaction_setFrameTimeline(ASurfaceTransaction* transaction, + int64_t vsyncId) __INTRODUCED_IN(33); + __END_DECLS #endif // ANDROID_SURFACE_CONTROL_H diff --git a/libs/gui/FrameTimelineInfo.cpp b/libs/gui/FrameTimelineInfo.cpp index 9231a570fc..3800b88ab0 100644 --- a/libs/gui/FrameTimelineInfo.cpp +++ b/libs/gui/FrameTimelineInfo.cpp @@ -33,12 +33,14 @@ namespace android { status_t FrameTimelineInfo::write(Parcel& output) const { SAFE_PARCEL(output.writeInt64, vsyncId); SAFE_PARCEL(output.writeInt32, inputEventId); + SAFE_PARCEL(output.writeInt64, startTimeNanos); return NO_ERROR; } status_t FrameTimelineInfo::read(const Parcel& input) { SAFE_PARCEL(input.readInt64, &vsyncId); SAFE_PARCEL(input.readInt32, &inputEventId); + SAFE_PARCEL(input.readInt64, &startTimeNanos); return NO_ERROR; } @@ -48,16 +50,19 @@ void FrameTimelineInfo::merge(const FrameTimelineInfo& other) { if (other.vsyncId > vsyncId) { vsyncId = other.vsyncId; inputEventId = other.inputEventId; + startTimeNanos = other.startTimeNanos; } } else if (vsyncId == INVALID_VSYNC_ID) { vsyncId = other.vsyncId; inputEventId = other.inputEventId; + startTimeNanos = other.startTimeNanos; } } void FrameTimelineInfo::clear() { vsyncId = INVALID_VSYNC_ID; inputEventId = IInputConstants::INVALID_INPUT_EVENT_ID; + startTimeNanos = 0; } }; // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 353a91d062..20c41460d4 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1846,9 +1846,10 @@ int Surface::dispatchSetFrameTimelineInfo(va_list args) { ATRACE_CALL(); auto frameTimelineVsyncId = static_cast(va_arg(args, int64_t)); auto inputEventId = static_cast(va_arg(args, int32_t)); + auto startTimeNanos = static_cast(va_arg(args, int64_t)); ALOGV("Surface::%s", __func__); - return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId}); + return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId, startTimeNanos}); } bool Surface::transformToDisplayInverse() const { diff --git a/libs/gui/include/gui/FrameTimelineInfo.h b/libs/gui/include/gui/FrameTimelineInfo.h index a23c20248c..255ce568d2 100644 --- a/libs/gui/include/gui/FrameTimelineInfo.h +++ b/libs/gui/include/gui/FrameTimelineInfo.h @@ -36,6 +36,9 @@ struct FrameTimelineInfo { // not directly vendor available. int32_t inputEventId = 0; + // The current time in nanoseconds the application started to render the frame. + int64_t startTimeNanos = 0; + status_t write(Parcel& output) const; status_t read(const Parcel& input); diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 0bc2b5d312..a319769148 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1025,10 +1025,11 @@ static inline int native_window_set_frame_rate(struct ANativeWindow* window, flo } static inline int native_window_set_frame_timeline_info(struct ANativeWindow* window, - int64_t frameTimelineVsyncId, - int32_t inputEventId) { - return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, - frameTimelineVsyncId, inputEventId); + int64_t frameTimelineVsyncId, + int32_t inputEventId, + int64_t startTimeNanos) { + return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, frameTimelineVsyncId, + inputEventId, startTimeNanos); } // ------------------------------------------------------------------------------------------------ diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 0c4e1120fc..86e96d769c 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -667,7 +667,8 @@ void SurfaceFrame::traceActuals(int64_t displayFrameToken) const { packet->set_timestamp( static_cast(endTime - kPredictionExpiredStartTimeDelta)); } else { - packet->set_timestamp(static_cast(mPredictions.startTime)); + packet->set_timestamp(static_cast( + mActuals.startTime == 0 ? mPredictions.startTime : mActuals.startTime)); } auto* event = packet->set_frame_timeline_event(); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 495d585509..c3b2fa598f 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1253,6 +1253,7 @@ std::shared_ptr Layer::createSurfaceFrameForTransac getSequence(), mName, mTransactionName, /*isBuffer*/ false, getGameMode()); + surfaceFrame->setActualStartTime(info.startTimeNanos); // For Transactions, the post time is considered to be both queue and acquire fence time. surfaceFrame->setActualQueueTime(postTime); surfaceFrame->setAcquireFenceTime(postTime); @@ -1270,6 +1271,7 @@ std::shared_ptr Layer::createSurfaceFrameForBuffer( mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, getSequence(), mName, debugName, /*isBuffer*/ true, getGameMode()); + surfaceFrame->setActualStartTime(info.startTimeNanos); // For buffers, acquire fence time will set during latch. surfaceFrame->setActualQueueTime(queueTime); const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); -- cgit v1.2.3-59-g8ed1b From cdf6cbc6595a675c01e112833d074eb0e22d037c Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 1 Nov 2021 17:21:15 -0700 Subject: End-to-end plumbing for dimming SDR layers Model here is: * HDR luminance is set to the current display brightness * SDR luminance is set to the current SDR white point reported by DisplayManager Ideally we use scene-referred white points instead, so: * PQ is always 10k nits * HLG is always 1k nits * Everything else is 150-200 nits So relative dimming thresholds are fixed. But right now this is visually less jarring (otherwise youtube UI will suddenly dim when autoplaying HDR video). Bug: 200310158 Test: Verified that plumbing sdr white point is sent to renderengine Test: librenderengine_test Test: libcompositionengine_test Test: DataspaceUtils_test Change-Id: I5bcea7941935c43e57cd5434e1ec69b41d31f2b4 --- .../include/renderengine/DisplaySettings.h | 6 +- .../include/renderengine/LayerSettings.h | 6 + libs/renderengine/skia/SkiaGLRenderEngine.cpp | 102 ++++++++++----- libs/renderengine/skia/SkiaGLRenderEngine.h | 14 +- libs/renderengine/tests/RenderEngineTest.cpp | 142 +++++++++++++++++++++ libs/ui/include_types/ui/DataspaceUtils.h | 29 +++++ libs/ui/tests/Android.bp | 10 ++ libs/ui/tests/DataspaceUtils_test.cpp | 53 ++++++++ .../include/compositionengine/LayerFE.h | 3 + .../include/compositionengine/impl/Display.h | 2 +- .../impl/OutputCompositionState.h | 3 + .../impl/OutputLayerCompositionState.h | 4 + .../CompositionEngine/src/Display.cpp | 7 +- .../CompositionEngine/src/Output.cpp | 5 +- .../CompositionEngine/src/OutputLayer.cpp | 21 +++ .../CompositionEngine/src/planner/CachedSet.cpp | 2 + .../CompositionEngine/tests/DisplayTest.cpp | 6 +- .../CompositionEngine/tests/MockHWC2.h | 1 + .../CompositionEngine/tests/OutputLayerTest.cpp | 33 ++++- .../CompositionEngine/tests/OutputTest.cpp | 59 ++++++--- .../tests/planner/CachedSetTest.cpp | 58 ++++++++- .../DisplayHardware/AidlComposerHal.cpp | 11 +- .../DisplayHardware/AidlComposerHal.h | 7 +- .../surfaceflinger/DisplayHardware/ComposerHal.h | 6 +- services/surfaceflinger/DisplayHardware/HWC2.cpp | 16 ++- services/surfaceflinger/DisplayHardware/HWC2.h | 11 +- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 6 +- .../surfaceflinger/DisplayHardware/HWComposer.h | 1 + .../DisplayHardware/HidlComposerHal.cpp | 8 +- .../DisplayHardware/HidlComposerHal.h | 7 +- services/surfaceflinger/Layer.cpp | 3 + services/surfaceflinger/SurfaceFlinger.cpp | 10 +- .../unittests/mock/DisplayHardware/MockComposer.h | 4 +- .../unittests/mock/DisplayHardware/MockHWC2.h | 4 +- 34 files changed, 569 insertions(+), 91 deletions(-) create mode 100644 libs/ui/include_types/ui/DataspaceUtils.h create mode 100644 libs/ui/tests/DataspaceUtils_test.cpp (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index d395d06b95..b4cab39bd9 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -57,8 +57,10 @@ struct DisplaySettings { // orientation. uint32_t orientation = ui::Transform::ROT_0; - // SDR white point, -1f if unknown - float sdrWhitePointNits = -1.f; + // Target luminance of the display. -1f if unknown. + // All layers will be dimmed by (max(layer white points) / targetLuminanceNits). + // If the target luminance is unknown, then no display-level dimming occurs. + float targetLuminanceNits = -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 715f3f84ae..702e8b0c6c 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -171,6 +171,12 @@ struct LayerSettings { // Name associated with the layer for debugging purposes. std::string name; + + // Luminance of the white point for this layer. Used for linear dimming. + // Individual layers will be dimmed by (whitePointNits / maxWhitePoint). + // If white point nits are unknown, then this layer is assumed to have the + // same luminance as the brightest layer in the scene. + float whitePointNits = -1.f; }; // Keep in sync with custom comparison function in diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 376e279473..cc90946753 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include "../gl/GLExtensions.h" #include "Cache.h" @@ -612,33 +613,33 @@ private: AutoBackendTexture::CleanupManager& mMgr; }; -sk_sp SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp shader, - const LayerSettings& layer, - const DisplaySettings& display, - bool undoPremultipliedAlpha, - bool requiresLinearEffect) { - const auto stretchEffect = layer.stretchEffect; +sk_sp SkiaGLRenderEngine::createRuntimeEffectShader( + const RuntimeEffectShaderParameters& parameters) { // The given surface will be stretched by HWUI via matrix transformation // which gets similar results for most surfaces // Determine later on if we need to leverage the stertch shader within // surface flinger + const auto& stretchEffect = parameters.layer.stretchEffect; + auto shader = parameters.shader; if (stretchEffect.hasEffect()) { - const auto targetBuffer = layer.source.buffer.buffer; + const auto targetBuffer = parameters.layer.source.buffer.buffer; const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr; - if (graphicBuffer && shader) { + if (graphicBuffer && parameters.shader) { shader = mStretchShaderFactory.createSkShader(shader, stretchEffect); } } - if (requiresLinearEffect) { - const ui::Dataspace inputDataspace = - mUseColorManagement ? layer.sourceDataspace : ui::Dataspace::V0_SRGB_LINEAR; - const ui::Dataspace outputDataspace = - mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR; + if (parameters.requiresLinearEffect) { + const ui::Dataspace inputDataspace = mUseColorManagement ? parameters.layer.sourceDataspace + : ui::Dataspace::V0_SRGB_LINEAR; + const ui::Dataspace outputDataspace = mUseColorManagement + ? parameters.display.outputDataspace + : ui::Dataspace::V0_SRGB_LINEAR; - auto effect = shaders::LinearEffect{.inputDataspace = inputDataspace, - .outputDataspace = outputDataspace, - .undoPremultipliedAlpha = undoPremultipliedAlpha}; + auto effect = + shaders::LinearEffect{.inputDataspace = inputDataspace, + .outputDataspace = outputDataspace, + .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha}; auto effectIter = mRuntimeEffects.find(effect); sk_sp runtimeEffect = nullptr; @@ -648,16 +649,16 @@ 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, maxLuminance); + mat4 colorTransform = parameters.layer.colorTransform; + + colorTransform *= + mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio, + parameters.layerDimmingRatio, 1.f)); + return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform, + parameters.display.maxLuminance, + parameters.layer.source.buffer.maxLuminanceNits); } - return shader; + return parameters.shader; } void SkiaGLRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) { @@ -730,6 +731,11 @@ static SkRRect getBlurRRect(const BlurRegion& region) { return roundedRect; } +static bool equalsWithinMargin(float expected, float value, float margin) { + LOG_ALWAYS_FATAL_IF(margin < 0.f, "Margin is negative!"); + return std::abs(expected - value) < margin; +} + void SkiaGLRenderEngine::drawLayersInternal( const std::shared_ptr>&& resultPromise, const DisplaySettings& display, const std::vector& layers, @@ -791,6 +797,18 @@ void SkiaGLRenderEngine::drawLayersInternal( const bool ctModifiesAlpha = displayColorTransform && !displayColorTransform->isAlphaUnchanged(); + // Find the max layer white point to determine the max luminance of the scene... + const float maxLayerWhitePoint = std::transform_reduce( + layers.cbegin(), layers.cend(), 0.f, + [](float left, float right) { return std::max(left, right); }, + [&](const auto& l) { return l.whitePointNits; }); + + // ...and compute the dimming ratio if dimming is requested + const float displayDimmingRatio = display.targetLuminanceNits > 0.f && + maxLayerWhitePoint > 0.f && display.targetLuminanceNits > maxLayerWhitePoint + ? maxLayerWhitePoint / display.targetLuminanceNits + : 1.f; + // Find if any layers have requested blur, we'll use that info to decide when to render to an // offscreen buffer and when to render to the native buffer. sk_sp activeSurface(dstSurface); @@ -964,11 +982,14 @@ void SkiaGLRenderEngine::drawLayersInternal( drawShadow(canvas, rrect, layer.shadow); } + const float layerDimmingRatio = layer.whitePointNits <= 0.f + ? displayDimmingRatio + : (layer.whitePointNits / maxLayerWhitePoint) * displayDimmingRatio; + const bool requiresLinearEffect = layer.colorTransform != mat4() || (mUseColorManagement && needsToneMapping(layer.sourceDataspace, display.outputDataspace)) || - (display.sdrWhitePointNits > 0.f && - display.sdrWhitePointNits != display.maxLuminance); + !equalsWithinMargin(1.f, layerDimmingRatio, 0.001f); // quick abort from drawing the remaining portion of the layer if (layer.skipContentDraw || @@ -1067,9 +1088,20 @@ void SkiaGLRenderEngine::drawLayersInternal( toSkColorSpace(layerDataspace))); } - paint.setShader(createRuntimeEffectShader(shader, layer, display, - !item.isOpaque && item.usePremultipliedAlpha, - requiresLinearEffect)); + paint.setShader(createRuntimeEffectShader( + RuntimeEffectShaderParameters{.shader = shader, + .layer = layer, + .display = display, + .undoPremultipliedAlpha = !item.isOpaque && + item.usePremultipliedAlpha, + .requiresLinearEffect = requiresLinearEffect, + .layerDimmingRatio = layerDimmingRatio})); + + // Turn on dithering when dimming beyond this threshold. + static constexpr float kDimmingThreshold = 0.2f; + if (layerDimmingRatio <= kDimmingThreshold) { + paint.setDither(true); + } paint.setAlphaf(layer.alpha); } else { ATRACE_NAME("DrawColor"); @@ -1079,9 +1111,13 @@ void SkiaGLRenderEngine::drawLayersInternal( .fB = color.b, .fA = layer.alpha}, toSkColorSpace(layerDataspace)); - paint.setShader(createRuntimeEffectShader(shader, layer, display, - /* undoPremultipliedAlpha */ false, - requiresLinearEffect)); + paint.setShader(createRuntimeEffectShader( + RuntimeEffectShaderParameters{.shader = shader, + .layer = layer, + .display = display, + .undoPremultipliedAlpha = false, + .requiresLinearEffect = requiresLinearEffect, + .layerDimmingRatio = layerDimmingRatio})); } if (layer.disableBlending) { diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 53792f9731..a650313648 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -106,12 +106,18 @@ private: void initCanvas(SkCanvas* canvas, const DisplaySettings& display); void drawShadow(SkCanvas* canvas, const SkRRect& casterRRect, const ShadowSettings& shadowSettings); + // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned. // Otherwise it returns the input shader. - sk_sp createRuntimeEffectShader(sk_sp shader, const LayerSettings& layer, - const DisplaySettings& display, - bool undoPremultipliedAlpha, - bool requiresLinearEffect); + struct RuntimeEffectShaderParameters { + sk_sp shader; + const LayerSettings& layer; + const DisplaySettings& display; + bool undoPremultipliedAlpha; + bool requiresLinearEffect; + float layerDimmingRatio; + }; + sk_sp createRuntimeEffectShader(const RuntimeEffectShaderParameters&); EGLDisplay mEGLDisplay; EGLContext mEGLContext; diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 82590638a8..eb2b2dcbfa 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -208,6 +208,21 @@ public: renderengine::ExternalTexture::Usage::WRITEABLE); } + std::shared_ptr allocateAndFillSourceBuffer(uint32_t width, + uint32_t height, + ubyte4 color) { + const auto buffer = allocateSourceBuffer(width, height); + uint8_t* pixels; + buffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + reinterpret_cast(&pixels)); + pixels[0] = color.r; + pixels[1] = color.g; + pixels[2] = color.b; + pixels[3] = color.a; + buffer->getBuffer()->unlock(); + return buffer; + } + RenderEngineTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); @@ -2195,6 +2210,133 @@ TEST_P(RenderEngineTest, testDisableBlendingBuffer) { expectBufferColor(rect, 0, 128, 0, 128); } +TEST_P(RenderEngineTest, testDimming) { + if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { + return; + } + initializeRenderEngine(); + + const auto displayRect = Rect(3, 1); + const renderengine::DisplaySettings display{ + .physicalDisplay = displayRect, + .clip = displayRect, + .outputDataspace = ui::Dataspace::V0_SRGB_LINEAR, + .targetLuminanceNits = 1000.f, + }; + + const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255)); + const auto blueBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 0, 255, 255)); + const auto redBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(255, 0, 0, 255)); + + const renderengine::LayerSettings greenLayer{ + .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f), + .source = + renderengine::PixelSource{ + .buffer = + renderengine::Buffer{ + .buffer = greenBuffer, + .usePremultipliedAlpha = true, + }, + }, + .alpha = 1.0f, + .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR, + .whitePointNits = 200.f, + }; + + const renderengine::LayerSettings blueLayer{ + .geometry.boundaries = FloatRect(1.f, 0.f, 2.f, 1.f), + .source = + renderengine::PixelSource{ + .buffer = + renderengine::Buffer{ + .buffer = blueBuffer, + .usePremultipliedAlpha = true, + }, + }, + .alpha = 1.0f, + .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR, + .whitePointNits = 1000.f / 51.f, + }; + + const renderengine::LayerSettings redLayer{ + .geometry.boundaries = FloatRect(2.f, 0.f, 3.f, 1.f), + .source = + renderengine::PixelSource{ + .buffer = + renderengine::Buffer{ + .buffer = redBuffer, + .usePremultipliedAlpha = true, + }, + }, + .alpha = 1.0f, + .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR, + // When the white point is not set for a layer, just ignore it and treat it as the same + // as the max layer + .whitePointNits = -1.f, + }; + + std::vector layers{greenLayer, blueLayer, redLayer}; + invokeDraw(display, layers); + + expectBufferColor(Rect(1, 1), 0, 51, 0, 255, 1); + expectBufferColor(Rect(1, 0, 2, 1), 0, 0, 5, 255, 1); + expectBufferColor(Rect(2, 0, 3, 1), 51, 0, 0, 255, 1); +} + +TEST_P(RenderEngineTest, testDimming_withoutTargetLuminance) { + initializeRenderEngine(); + if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { + return; + } + + const auto displayRect = Rect(2, 1); + const renderengine::DisplaySettings display{ + .physicalDisplay = displayRect, + .clip = displayRect, + .outputDataspace = ui::Dataspace::V0_SRGB_LINEAR, + .targetLuminanceNits = -1.f, + }; + + const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255)); + const auto blueBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 0, 255, 255)); + + const renderengine::LayerSettings greenLayer{ + .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f), + .source = + renderengine::PixelSource{ + .buffer = + renderengine::Buffer{ + .buffer = greenBuffer, + .usePremultipliedAlpha = true, + }, + }, + .alpha = 1.0f, + .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR, + .whitePointNits = 200.f, + }; + + const renderengine::LayerSettings blueLayer{ + .geometry.boundaries = FloatRect(1.f, 0.f, 2.f, 1.f), + .source = + renderengine::PixelSource{ + .buffer = + renderengine::Buffer{ + .buffer = blueBuffer, + .usePremultipliedAlpha = true, + }, + }, + .alpha = 1.0f, + .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR, + .whitePointNits = 1000.f, + }; + + std::vector layers{greenLayer, blueLayer}; + invokeDraw(display, layers); + + expectBufferColor(Rect(1, 1), 0, 51, 0, 255, 1); + expectBufferColor(Rect(1, 0, 2, 1), 0, 0, 255, 255); +} + TEST_P(RenderEngineTest, test_isOpaque) { initializeRenderEngine(); diff --git a/libs/ui/include_types/ui/DataspaceUtils.h b/libs/ui/include_types/ui/DataspaceUtils.h new file mode 100644 index 0000000000..a461cb4e68 --- /dev/null +++ b/libs/ui/include_types/ui/DataspaceUtils.h @@ -0,0 +1,29 @@ +/* + * 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 + +namespace android { + +inline bool isHdrDataspace(ui::Dataspace dataspace) { + const auto transfer = dataspace & HAL_DATASPACE_TRANSFER_MASK; + + return transfer == HAL_DATASPACE_TRANSFER_ST2084 || transfer == HAL_DATASPACE_TRANSFER_HLG; +} + +} // namespace android \ No newline at end of file diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 0ee15f26cf..22fbf45c8c 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -163,3 +163,13 @@ cc_test { "-Werror", ], } + +cc_test { + name: "DataspaceUtils_test", + shared_libs: ["libui"], + srcs: ["DataspaceUtils_test.cpp"], + cflags: [ + "-Wall", + "-Werror", + ], +} diff --git a/libs/ui/tests/DataspaceUtils_test.cpp b/libs/ui/tests/DataspaceUtils_test.cpp new file mode 100644 index 0000000000..3e0967182b --- /dev/null +++ b/libs/ui/tests/DataspaceUtils_test.cpp @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#undef LOG_TAG +#define LOG_TAG "DataspaceUtilsTest" + +#include +#include + +namespace android { + +class DataspaceUtilsTest : public testing::Test {}; + +TEST_F(DataspaceUtilsTest, isHdrDataspace) { + EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_ITU_HLG)); + EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_ITU_PQ)); + EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_PQ)); + EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_HLG)); + + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SRGB_LINEAR)); + // scRGB defines a very wide gamut but not an expanded luminance range + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SCRGB_LINEAR)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SRGB)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SCRGB)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_JFIF)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_BT601_625)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_BT601_525)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_BT709)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DCI_P3_LINEAR)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DCI_P3)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DISPLAY_P3_LINEAR)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DISPLAY_P3)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::ADOBE_RGB)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::BT2020_LINEAR)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::BT2020)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::BT2020_ITU)); + EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DISPLAY_BT2020)); +} + +} // namespace android diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index ac243c0a17..e77e155cb8 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -134,6 +134,9 @@ public: // Configure layer settings for using blurs BlurSetting blurSetting; + + // Requested white point of the layer in nits + const float whitePointNits; }; // A superset of LayerSettings required by RenderEngine to compose a layer diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index b407267560..3571e11ad1 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -76,7 +76,7 @@ public: virtual void applyChangedTypesToLayers(const ChangedTypes&); virtual void applyDisplayRequests(const DisplayRequests&); virtual void applyLayerRequestsToLayers(const LayerRequests&); - virtual void applyClientTargetRequests(const ClientTargetProperty&); + virtual void applyClientTargetRequests(const ClientTargetProperty&, float whitePointNits); // Internal virtual void setConfiguration(const compositionengine::DisplayCreationArgs&); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 44f754f936..c5b6443728 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -127,6 +127,9 @@ struct OutputCompositionState { // SDR white point float sdrWhitePointNits{-1.f}; + // White point of the client target + float clientTargetWhitePointNits{-1.f}; + // Debugging void dump(std::string& result) const; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index 7564c54218..627b80bcc2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -146,6 +146,10 @@ struct OutputLayerCompositionState { // Timestamp for when the layer is queued for client composition nsecs_t clientCompositionTimestamp{0}; + + // White point of the layer, in nits. + static constexpr float kDefaultWhitePointNits = 200.f; + float whitePointNits = kDefaultWhitePointNits; }; } // namespace compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 02fa49f3c0..4603e6bc3e 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -237,7 +237,8 @@ void Display::chooseCompositionStrategy() { applyChangedTypesToLayers(changes->changedTypes); applyDisplayRequests(changes->displayRequests); applyLayerRequestsToLayers(changes->layerRequests); - applyClientTargetRequests(changes->clientTargetProperty); + applyClientTargetRequests(changes->clientTargetProperty, + changes->clientTargetWhitePointNits); } // Determine what type of composition we are doing from the final state @@ -309,12 +310,14 @@ void Display::applyLayerRequestsToLayers(const LayerRequests& layerRequests) { } } -void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty) { +void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty, + float whitePointNits) { if (clientTargetProperty.dataspace == ui::Dataspace::UNKNOWN) { return; } editState().dataspace = clientTargetProperty.dataspace; + editState().clientTargetWhitePointNits = whitePointNits; getRenderSurface()->setBufferDataspace(clientTargetProperty.dataspace); getRenderSurface()->setBufferPixelFormat(clientTargetProperty.pixelFormat); } diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 6800004a90..d50315391a 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -1057,7 +1057,7 @@ std::optional Output::composeSurfaces( clientCompositionDisplay.maxLuminance = outputState.displayBrightnessNits > 0.f ? outputState.displayBrightnessNits : mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance(); - clientCompositionDisplay.sdrWhitePointNits = outputState.sdrWhitePointNits; + clientCompositionDisplay.targetLuminanceNits = outputState.clientTargetWhitePointNits; // Compute the global color transform matrix. if (!outputState.usesDeviceComposition && !getSkipColorTransform()) { @@ -1217,7 +1217,8 @@ std::vector Output::generateClientCompositionRequests( .dataspace = outputDataspace, .realContentIsVisible = realContentIsVisible, .clearContent = !clientComposition, - .blurSetting = blurSetting}; + .blurSetting = blurSetting, + .whitePointNits = layerState.whitePointNits}; results = layerFE.prepareClientCompositionList(targetSettings); if (realContentIsVisible && !results.empty()) { layer->editState().clientCompositionTimestamp = systemTime(); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index cf761835a6..b010d9f965 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -24,6 +24,9 @@ #include #include #include +#include "system/graphics-base-v1.0.h" + +#include // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push @@ -317,6 +320,14 @@ void OutputLayer::updateCompositionState( ? outputState.targetDataspace : layerFEState->dataspace; + // For hdr content, treat the white point as the display brightness - HDR content should not be + // boosted or dimmed. + if (isHdrDataspace(state.dataspace)) { + state.whitePointNits = getOutput().getState().displayBrightnessNits; + } else { + state.whitePointNits = getOutput().getState().sdrWhitePointNits; + } + // These are evaluated every frame as they can potentially change at any // time. if (layerFEState->forceClientComposition || !profile.isDataspaceSupported(state.dataspace) || @@ -479,6 +490,16 @@ void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) ALOGE("[%s] Failed to set dataspace %d: %s (%d)", getLayerFE().getDebugName(), dataspace, to_string(error).c_str(), static_cast(error)); } + + // Don't dim cached layers + const auto whitePointNits = outputDependentState.overrideInfo.buffer + ? getOutput().getState().displayBrightnessNits + : outputDependentState.whitePointNits; + + if (auto error = hwcLayer->setWhitePointNits(whitePointNits); error != hal::Error::NONE) { + ALOGE("[%s] Failed to set white point %f: %s (%d)", getLayerFE().getDebugName(), + whitePointNits, to_string(error).c_str(), static_cast(error)); + } } void OutputLayer::writeOutputIndependentPerFrameStateToHWC( diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index ff96d94670..2203f22263 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -170,6 +170,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te .clip = viewport, .outputDataspace = outputDataspace, .orientation = orientation, + .targetLuminanceNits = outputState.displayBrightnessNits, }; LayerFE::ClientCompositionTargetSettings targetSettings{ @@ -182,6 +183,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te .realContentIsVisible = true, .clearContent = false, .blurSetting = LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + .whitePointNits = outputState.displayBrightnessNits, }; std::vector layerSettings; diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index ed235b8b57..568efce8b3 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -596,6 +596,7 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { hal::DisplayRequest::FLIP_CLIENT_TARGET, {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}}, {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN}, + -1.f, }; // Since two calls are made to anyLayersRequireClientComposition with different return @@ -788,15 +789,18 @@ TEST_F(DisplayApplyLayerRequestsToLayersTest, applyClientTargetRequests) { .dataspace = hal::Dataspace::STANDARD_BT470M, }; + static constexpr float kWhitePointNits = 800.f; + mock::RenderSurface* renderSurface = new StrictMock(); mDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); EXPECT_CALL(*renderSurface, setBufferPixelFormat(clientTargetProperty.pixelFormat)); EXPECT_CALL(*renderSurface, setBufferDataspace(clientTargetProperty.dataspace)); - mDisplay->applyClientTargetRequests(clientTargetProperty); + mDisplay->applyClientTargetRequests(clientTargetProperty, kWhitePointNits); auto& state = mDisplay->getState(); EXPECT_EQ(clientTargetProperty.dataspace, state.dataspace); + EXPECT_EQ(kWhitePointNits, state.clientTargetWhitePointNits); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h index 95186599fc..9e08f9eddc 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h @@ -71,6 +71,7 @@ public: MOCK_METHOD1(setColorTransform, Error(const android::mat4&)); MOCK_METHOD3(setLayerGenericMetadata, Error(const std::string&, bool, const std::vector&)); + MOCK_METHOD1(setWhitePointNits, Error(float)); }; } // namespace mock diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index fd584fd522..207c31e756 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -652,6 +652,22 @@ TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceCorrectly EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace); } +TEST_F(OutputLayerUpdateCompositionStateTest, setsWhitePointNitsCorrectly) { + mOutputState.sdrWhitePointNits = 200.f; + mOutputState.displayBrightnessNits = 800.f; + + mLayerFEState.dataspace = ui::Dataspace::DISPLAY_P3; + mLayerFEState.isColorspaceAgnostic = false; + mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0); + EXPECT_EQ(mOutputState.sdrWhitePointNits, mOutputLayer.getState().whitePointNits); + + mLayerFEState.dataspace = ui::Dataspace::BT2020_ITU_PQ; + mLayerFEState.isColorspaceAgnostic = false; + mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0); + + EXPECT_EQ(mOutputState.displayBrightnessNits, mOutputLayer.getState().whitePointNits); +} + TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) { mOutputLayer.editState().forceClientComposition = false; @@ -728,6 +744,8 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static constexpr int kOverrideHwcSlot = impl::HwcBufferCache::FLATTENER_CACHING_SLOT; static constexpr bool kLayerGenericMetadata1Mandatory = true; static constexpr bool kLayerGenericMetadata2Mandatory = true; + static constexpr float kWhitePointNits = 200.f; + static constexpr float kDisplayBrightnessNits = 400.f; static const half4 kColor; static const Rect kDisplayFrame; @@ -758,6 +776,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { outputLayerState.bufferTransform = static_cast(kBufferTransform); outputLayerState.outputSpaceVisibleRegion = kOutputSpaceVisibleRegion; outputLayerState.dataspace = kDataspace; + outputLayerState.whitePointNits = kWhitePointNits; mLayerFEState.blendMode = kBlendMode; mLayerFEState.alpha = kAlpha; @@ -770,6 +789,8 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { mLayerFEState.bufferSlot = BufferQueue::INVALID_BUFFER_SLOT; mLayerFEState.acquireFence = kFence; + mOutputState.displayBrightnessNits = kDisplayBrightnessNits; + EXPECT_CALL(mOutput, getDisplayColorProfile()) .WillRepeatedly(Return(&mDisplayColorProfile)); EXPECT_CALL(mDisplayColorProfile, getSupportedPerFrameMetadata()) @@ -818,9 +839,11 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None, ui::Dataspace dataspace = kDataspace, const Region& visibleRegion = kOutputSpaceVisibleRegion, - const Region& surfaceDamage = kSurfaceDamage) { + const Region& surfaceDamage = kSurfaceDamage, + float whitePointNits = kWhitePointNits) { EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(visibleRegion))).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setDataspace(dataspace)).WillOnce(Return(kError)); + EXPECT_CALL(*mHwcLayer, setWhitePointNits(whitePointNits)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform)) .WillOnce(Return(unsupported == SimulateUnsupported::ColorTransform ? hal::Error::UNSUPPORTED @@ -1084,7 +1107,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerDoesNotSendBuffer) { expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform, kOverrideBlendMode, kSkipAlpha); expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion, - kOverrideSurfaceDamage); + kOverrideSurfaceDamage, kDisplayBrightnessNits); expectSetHdrMetadataAndBufferCalls(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false)); @@ -1100,7 +1123,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerForSolidColorDoesNotSe expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform, kOverrideBlendMode, kSkipAlpha); expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion, - kOverrideSurfaceDamage); + kOverrideSurfaceDamage, kDisplayBrightnessNits); expectSetHdrMetadataAndBufferCalls(); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false)); @@ -1116,7 +1139,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform, kOverrideBlendMode, kOverrideAlpha); expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion, - kOverrideSurfaceDamage); + kOverrideSurfaceDamage, kDisplayBrightnessNits); expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false)); @@ -1132,7 +1155,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoForSolidColorIfPresen expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform, kOverrideBlendMode, kOverrideAlpha); expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion, - kOverrideSurfaceDamage); + kOverrideSurfaceDamage, kDisplayBrightnessNits); expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false)); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index cf63ef5183..6d96260de7 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -3023,6 +3023,7 @@ struct OutputComposeSurfacesTest : public testing::Test { mOutput.mState.usesDeviceComposition = false; mOutput.mState.reusedClientComposition = false; mOutput.mState.flipClientTarget = false; + mOutput.mState.clientTargetWhitePointNits = kClientTargetLuminanceNits; EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine)); EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine)); @@ -3057,6 +3058,7 @@ struct OutputComposeSurfacesTest : public testing::Test { static constexpr float kDefaultMaxLuminance = 0.9f; static constexpr float kDefaultAvgLuminance = 0.7f; static constexpr float kDefaultMinLuminance = 0.1f; + static constexpr float kClientTargetLuminanceNits = 200.f; static const Rect kDefaultOutputFrame; static const Rect kDefaultOutputViewport; @@ -3424,7 +3426,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedComposi .andIfSkipColorTransform(false) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), - kDefaultOutputOrientationFlags}) + kDefaultOutputOrientationFlags, + kClientTargetLuminanceNits}) .execute() .expectAFenceWasReturned(); } @@ -3435,7 +3438,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComp .andIfSkipColorTransform(false) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), - kDefaultOutputOrientationFlags}) + kDefaultOutputOrientationFlags, + kClientTargetLuminanceNits}) .execute() .expectAFenceWasReturned(); } @@ -3444,10 +3448,10 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientCo verify().ifMixedCompositionIs(false) .andIfUsesHdr(true) .andIfSkipColorTransform(false) - .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, - kDefaultMaxLuminance, kDefaultOutputDataspace, - kDefaultColorTransformMat, - kDefaultOutputOrientationFlags}) + .thenExpectDisplaySettingsUsed( + {kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, + kDefaultOutputDataspace, kDefaultColorTransformMat, + kDefaultOutputOrientationFlags, kClientTargetLuminanceNits}) .execute() .expectAFenceWasReturned(); } @@ -3456,10 +3460,10 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrOnlyClien verify().ifMixedCompositionIs(false) .andIfUsesHdr(false) .andIfSkipColorTransform(false) - .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, - kDefaultMaxLuminance, kDefaultOutputDataspace, - kDefaultColorTransformMat, - kDefaultOutputOrientationFlags}) + .thenExpectDisplaySettingsUsed( + {kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, + kDefaultOutputDataspace, kDefaultColorTransformMat, + kDefaultOutputOrientationFlags, kClientTargetLuminanceNits}) .execute() .expectAFenceWasReturned(); } @@ -3471,7 +3475,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, .andIfSkipColorTransform(true) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), - kDefaultOutputOrientationFlags}) + kDefaultOutputOrientationFlags, + kClientTargetLuminanceNits}) .execute() .expectAFenceWasReturned(); } @@ -3729,6 +3734,8 @@ struct GenerateClientCompositionRequestsTest : public testing::Test { mOutput.setRenderSurfaceForTest(std::unique_ptr(mRenderSurface)); } + static constexpr float kLayerWhitePointNits = 200.f; + mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock(); mock::RenderSurface* mRenderSurface = new StrictMock(); StrictMock mOutput; @@ -3768,6 +3775,7 @@ struct GenerateClientCompositionRequestsTest_ThreeLayers static constexpr ui::Rotation kDisplayOrientation = ui::ROTATION_0; static constexpr ui::Dataspace kDisplayDataspace = ui::Dataspace::UNKNOWN; + static constexpr float kLayerWhitePointNits = 200.f; static const Rect kDisplayFrame; static const Rect kDisplayViewport; @@ -3930,14 +3938,15 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqu compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), - false, /* needs filtering */ - false, /* secure */ - false, /* supports protected content */ + false, /* needs filtering */ + false, /* secure */ + false, /* supports protected content */ kDisplayViewport, kDisplayDataspace, false /* realContentIsVisible */, true /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), @@ -3949,6 +3958,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqu true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; LayerFE::LayerSettings mBlackoutSettings = mLayers[1].mLayerSettings; @@ -3988,6 +3998,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(Rect(0, 0, 30, 30)), @@ -3999,6 +4010,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(Rect(0, 0, 40, 201)), @@ -4010,6 +4022,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) @@ -4039,6 +4052,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), @@ -4050,6 +4064,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), @@ -4061,6 +4076,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) @@ -4090,7 +4106,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, - + kLayerWhitePointNits, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), @@ -4102,6 +4118,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), @@ -4113,6 +4130,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) @@ -4141,6 +4159,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), @@ -4152,6 +4171,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), @@ -4163,6 +4183,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) @@ -4179,7 +4200,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, protectedContentSupportUsedToGenerateRequests) { - compositionengine::LayerFE::ClientCompositionTargetSettings layer0TargetSettings{ Region(kDisplayFrame), false, /* needs filtering */ @@ -4190,6 +4210,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{ Region(kDisplayFrame), @@ -4201,6 +4222,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{ Region(kDisplayFrame), @@ -4212,6 +4234,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings)))) @@ -4379,6 +4402,7 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; EXPECT_CALL(leftLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true)); @@ -4396,6 +4420,7 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; EXPECT_CALL(rightLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true)); @@ -4428,6 +4453,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; LayerFE::LayerSettings mShadowSettings; @@ -4472,6 +4498,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true /* realContentIsVisible */, false /* clearContent */, compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled, + kLayerWhitePointNits, }; EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false)); diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index 42b3d972a8..d5a117a597 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -55,13 +55,21 @@ MATCHER_P(ClientCompositionTargetSettingsBlurSettingsEq, expectedBlurSetting, "" } MATCHER_P(ClientCompositionTargetSettingsSecureEq, expectedSecureSetting, "") { - *result_listener << "ClientCompositionTargetSettings' SecureSettings aren't equal \n"; + *result_listener << "ClientCompositionTargetSettings' isSecure bits aren't equal \n"; *result_listener << "expected " << expectedSecureSetting << "\n"; *result_listener << "actual " << arg.isSecure << "\n"; return expectedSecureSetting == arg.isSecure; } +MATCHER_P(ClientCompositionTargetSettingsWhitePointEq, expectedWhitePoint, "") { + *result_listener << "ClientCompositionTargetSettings' white points aren't equal \n"; + *result_listener << "expected " << expectedWhitePoint << "\n"; + *result_listener << "actual " << arg.whitePointNits << "\n"; + + return expectedWhitePoint == arg.whitePointNits; +} + static const ui::Size kOutputSize = ui::Size(1, 1); class CachedSetTest : public testing::Test { @@ -431,6 +439,54 @@ TEST_F(CachedSetTest, renderSecureOutput) { cachedSet.append(CachedSet(layer3)); } +TEST_F(CachedSetTest, renderWhitePoint) { + // Skip the 0th layer to ensure that the bounding box of the layers is offset from (0, 0) + CachedSet::Layer& layer1 = *mTestLayers[1]->cachedSetLayer.get(); + sp layerFE1 = mTestLayers[1]->layerFE; + CachedSet::Layer& layer2 = *mTestLayers[2]->cachedSetLayer.get(); + sp layerFE2 = mTestLayers[2]->layerFE; + + CachedSet cachedSet(layer1); + cachedSet.append(CachedSet(layer2)); + + std::vector clientCompList1; + clientCompList1.push_back({}); + + std::vector clientCompList2; + clientCompList2.push_back({}); + + mOutputState.displayBrightnessNits = 400.f; + + const auto drawLayers = + [&](const renderengine::DisplaySettings& displaySettings, + const std::vector&, + const std::shared_ptr&, const bool, + base::unique_fd&&) -> std::future { + EXPECT_EQ(mOutputState.displayBrightnessNits, displaySettings.targetLuminanceNits); + return futureOf({NO_ERROR, base::unique_fd()}); + }; + + EXPECT_CALL(*layerFE1, + prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq( + mOutputState.displayBrightnessNits))) + .WillOnce(Return(clientCompList1)); + EXPECT_CALL(*layerFE2, + prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq( + mOutputState.displayBrightnessNits))) + .WillOnce(Return(clientCompList2)); + EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers)); + mOutputState.isSecure = true; + cachedSet.render(mRenderEngine, mTexturePool, mOutputState); + expectReadyBuffer(cachedSet); + + EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace()); + EXPECT_EQ(Rect(kOutputSize.width, kOutputSize.height), cachedSet.getTextureBounds()); + + // Now check that appending a new cached set properly cleans up RenderEngine resources. + CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get(); + cachedSet.append(CachedSet(layer3)); +} + TEST_F(CachedSetTest, rendersWithOffsetFramebufferContent) { // Skip the 0th layer to ensure that the bounding box of the layers is offset from (0, 0) CachedSet::Layer& layer1 = *mTestLayers[1]->cachedSetLayer.get(); diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index 200bb65b29..29e5a7464d 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -1005,12 +1005,19 @@ V2_4::Error AidlComposer::getLayerGenericMetadataKeys( } Error AidlComposer::getClientTargetProperty( - Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) { + Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty, + float* whitePointNits) { ClientTargetProperty property; - mReader.takeClientTargetProperty(translate(display), &property); + mReader.takeClientTargetProperty(translate(display), &property, whitePointNits); *outClientTargetProperty = translate(property); return Error::NONE; } +Error AidlComposer::setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) { + mWriter.setLayerWhitePointNits(translate(display), translate(layer), + whitePointNits); + return Error::NONE; +} + } // namespace Hwc2 } // namespace android diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index 418a8cc18b..8cae25f742 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -194,9 +194,10 @@ public: bool mandatory, const std::vector& value) override; V2_4::Error getLayerGenericMetadataKeys( std::vector* outKeys) override; - Error getClientTargetProperty( - Display display, - IComposerClient::ClientTargetProperty* outClientTargetProperty) override; + Error getClientTargetProperty(Display display, + IComposerClient::ClientTargetProperty* outClientTargetProperty, + float* outClientTargetWhitePointNits) override; + Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override; private: // Many public functions above simply write a command into the command diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 3bbce7bbfa..3cc5e5e360 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -221,7 +221,11 @@ public: virtual V2_4::Error getLayerGenericMetadataKeys( std::vector* outKeys) = 0; virtual Error getClientTargetProperty( - Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0; + Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty, + float* outWhitePointNits) = 0; + + // AIDL Composer + virtual Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) = 0; }; } // namespace android::Hwc2 diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index e21b0daa96..596666c3f7 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -555,8 +555,10 @@ Error Display::setContentType(ContentType contentType) { return static_cast(intError); } -Error Display::getClientTargetProperty(ClientTargetProperty* outClientTargetProperty) { - const auto error = mComposer.getClientTargetProperty(mId, outClientTargetProperty); +Error Display::getClientTargetProperty(ClientTargetProperty* outClientTargetProperty, + float* outWhitePointNits) { + const auto error = + mComposer.getClientTargetProperty(mId, outClientTargetProperty, outWhitePointNits); return static_cast(error); } @@ -919,6 +921,16 @@ Error Layer::setLayerGenericMetadata(const std::string& name, bool mandatory, return static_cast(intError); } +// AIDL HAL +Error Layer::setWhitePointNits(float whitePointNits) { + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + + auto intError = mComposer.setLayerWhitePointNits(mDisplay->getId(), mId, whitePointNits); + return static_cast(intError); +} + } // namespace impl } // namespace HWC2 } // namespace android diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index a65efb2931..5e0ba06a0e 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -146,7 +146,7 @@ public: std::vector*) const = 0; [[clang::warn_unused_result]] virtual hal::Error setContentType(hal::ContentType) = 0; [[clang::warn_unused_result]] virtual hal::Error getClientTargetProperty( - hal::ClientTargetProperty* outClientTargetProperty) = 0; + hal::ClientTargetProperty* outClientTargetProperty, float* outWhitePointNits) = 0; }; namespace impl { @@ -209,7 +209,8 @@ public: hal::Error getSupportedContentTypes( std::vector* outSupportedContentTypes) const override; hal::Error setContentType(hal::ContentType) override; - hal::Error getClientTargetProperty(hal::ClientTargetProperty* outClientTargetProperty) override; + hal::Error getClientTargetProperty(hal::ClientTargetProperty* outClientTargetProperty, + float* outWhitePointNits) override; // Other Display methods hal::HWDisplayId getId() const override { return mId; } @@ -288,6 +289,9 @@ public: // Composer HAL 2.4 [[clang::warn_unused_result]] virtual hal::Error setLayerGenericMetadata( const std::string& name, bool mandatory, const std::vector& value) = 0; + + // AIDL HAL + [[clang::warn_unused_result]] virtual hal::Error setWhitePointNits(float whitePointNits) = 0; }; namespace impl { @@ -331,6 +335,9 @@ public: hal::Error setLayerGenericMetadata(const std::string& name, bool mandatory, const std::vector& value) override; + // AIDL HAL + hal::Error setWhitePointNits(float whitePointNits) override; + private: // These are references to data owned by HWC2::Device, which will outlive // this HWC2::Layer, so these references are guaranteed to be valid for diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 06f5df5e47..d851e22b59 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -522,11 +522,13 @@ status_t HWComposer::getDeviceCompositionChanges( RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX); DeviceRequestedChanges::ClientTargetProperty clientTargetProperty; - error = hwcDisplay->getClientTargetProperty(&clientTargetProperty); + float clientTargetWhitePointNits; + error = hwcDisplay->getClientTargetProperty(&clientTargetProperty, &clientTargetWhitePointNits); outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests), std::move(layerRequests), - std::move(clientTargetProperty)}); + std::move(clientTargetProperty), + clientTargetWhitePointNits}); error = hwcDisplay->acceptChanges(); RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 0a090da01e..bd79977bc9 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -79,6 +79,7 @@ public: DisplayRequests displayRequests; LayerRequests layerRequests; ClientTargetProperty clientTargetProperty; + float clientTargetWhitePointNits; }; struct HWCDisplayMode { diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index 6c405988e2..11d41c063e 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -1164,8 +1164,14 @@ V2_4::Error HidlComposer::getLayerGenericMetadataKeys( } Error HidlComposer::getClientTargetProperty( - Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) { + Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty, + float* outWhitePointNits) { mReader.takeClientTargetProperty(display, outClientTargetProperty); + *outWhitePointNits = -1.f; + return Error::NONE; +} + +Error HidlComposer::setLayerWhitePointNits(Display, Layer, float) { return Error::NONE; } diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index ad253a26b4..18c0635dd2 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -304,9 +304,10 @@ public: bool mandatory, const std::vector& value) override; V2_4::Error getLayerGenericMetadataKeys( std::vector* outKeys) override; - Error getClientTargetProperty( - Display display, - IComposerClient::ClientTargetProperty* outClientTargetProperty) override; + Error getClientTargetProperty(Display display, + IComposerClient::ClientTargetProperty* outClientTargetProperty, + float* outWhitePointNits) override; + Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override; private: class CommandWriter : public CommandWriterBase { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 4606746d4b..b39515955c 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -585,6 +586,8 @@ std::optional Layer::prepareClientCom layerSettings.alpha = alpha; layerSettings.sourceDataspace = getDataSpace(); + + layerSettings.whitePointNits = targetSettings.whitePointNits; switch (targetSettings.blurSetting) { case LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled: layerSettings.backgroundBlurRadius = getBackgroundBlurRadius(); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b7327b2faa..885d6986c3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -67,6 +67,7 @@ #include #include #include +#include #include #include #include @@ -2316,12 +2317,7 @@ void SurfaceFlinger::postComposition() { mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) { const auto layerFe = layer->getCompositionEngineLayerFE(); if (layer->isVisible() && compositionDisplay->includesLayer(layerFe)) { - const Dataspace transfer = - static_cast(layer->getDataSpace() & Dataspace::TRANSFER_MASK); - const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 || - transfer == Dataspace::TRANSFER_HLG); - - if (isHdr) { + if (isHdrDataspace(layer->getDataSpace())) { const auto* outputLayer = compositionDisplay->getOutputLayerForLayer(layerFe); if (outputLayer) { @@ -6425,6 +6421,8 @@ std::shared_future SurfaceFlinger::renderScree BlurSetting::Disabled : compositionengine::LayerFE::ClientCompositionTargetSettings:: BlurSetting::Enabled, + DisplayDevice::sDefaultMaxLumiance, + }; std::vector results = layer->prepareClientCompositionList(targetSettings); diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index 1ba3c0f56e..1debd65ac4 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -136,7 +136,9 @@ public: const std::vector&)); MOCK_METHOD1(getLayerGenericMetadataKeys, V2_4::Error(std::vector*)); - MOCK_METHOD2(getClientTargetProperty, Error(Display, IComposerClient::ClientTargetProperty*)); + MOCK_METHOD3(getClientTargetProperty, + Error(Display, IComposerClient::ClientTargetProperty*, float*)); + MOCK_METHOD3(setLayerWhitePointNits, Error(Display, Layer, float)); }; } // namespace Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h index fe1544ec18..83a0996fe6 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -85,7 +85,8 @@ public: MOCK_METHOD(hal::Error, getSupportedContentTypes, (std::vector *), (const, override)); MOCK_METHOD(hal::Error, setContentType, (hal::ContentType), (override)); - MOCK_METHOD(hal::Error, getClientTargetProperty, (hal::ClientTargetProperty *), (override)); + MOCK_METHOD(hal::Error, getClientTargetProperty, (hal::ClientTargetProperty *, float *), + (override)); }; class Layer : public HWC2::Layer { @@ -116,6 +117,7 @@ public: MOCK_METHOD(hal::Error, setColorTransform, (const android::mat4 &), (override)); MOCK_METHOD(hal::Error, setLayerGenericMetadata, (const std::string &, bool, const std::vector &), (override)); + MOCK_METHOD(hal::Error, setWhitePointNits, (float whitePointNits), (override)); }; } // namespace android::HWC2::mock -- cgit v1.2.3-59-g8ed1b From 2e1aa18498c9e7139c17849407d4743074632e9b Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Wed, 1 Dec 2021 17:33:12 -0500 Subject: Switch from HIDL Composition type to AIDL In preparation for adding a new Composition type which is only in AIDL. This change is almost completely mechanical, and should have no impact on behavior. Bug: 193170859 Test: existing tests Change-Id: I1f923fcc8d8e6dff388493a76e31d435638b5255 --- services/surfaceflinger/BufferLayer.cpp | 7 +- .../compositionengine/LayerFECompositionState.h | 5 +- .../include/compositionengine/OutputLayer.h | 5 +- .../include/compositionengine/impl/OutputLayer.h | 20 +- .../impl/OutputLayerCompositionState.h | 6 +- .../compositionengine/impl/planner/LayerState.h | 27 +-- .../compositionengine/impl/planner/Predictor.h | 4 +- .../include/compositionengine/mock/OutputLayer.h | 3 +- .../CompositionEngine/src/Display.cpp | 3 +- .../CompositionEngine/src/OutputLayer.cpp | 61 +++--- .../CompositionEngine/src/planner/Flattener.cpp | 3 +- .../CompositionEngine/src/planner/LayerState.cpp | 3 +- .../CompositionEngine/src/planner/Planner.cpp | 2 +- .../CompositionEngine/src/planner/Predictor.cpp | 36 ++-- .../CompositionEngine/tests/DisplayTest.cpp | 18 +- .../CompositionEngine/tests/MockHWC2.h | 5 +- .../CompositionEngine/tests/OutputLayerTest.cpp | 99 ++++----- .../tests/planner/LayerStateTest.cpp | 31 ++- .../tests/planner/PredictorTest.cpp | 20 +- .../DisplayHardware/AidlComposerHal.cpp | 14 +- .../DisplayHardware/AidlComposerHal.h | 13 +- .../surfaceflinger/DisplayHardware/ComposerHal.h | 9 +- services/surfaceflinger/DisplayHardware/HWC2.cpp | 4 +- services/surfaceflinger/DisplayHardware/HWC2.h | 15 +- .../surfaceflinger/DisplayHardware/HWComposer.h | 6 +- services/surfaceflinger/DisplayHardware/Hal.h | 18 +- .../DisplayHardware/HidlComposerHal.cpp | 19 +- .../DisplayHardware/HidlComposerHal.h | 20 +- services/surfaceflinger/EffectLayer.cpp | 3 +- services/surfaceflinger/Layer.cpp | 9 +- services/surfaceflinger/Layer.h | 3 +- .../tests/unittests/CompositionTest.cpp | 235 ++++++++++++--------- .../tests/unittests/TestableSurfaceFlinger.h | 3 +- .../unittests/mock/DisplayHardware/MockComposer.h | 6 +- .../unittests/mock/DisplayHardware/MockHWC2.h | 7 +- 35 files changed, 424 insertions(+), 318 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 64ddd687ad..e26c763f4e 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -292,14 +292,15 @@ void BufferLayer::preparePerFrameCompositionState() { // Sideband layers auto* compositionState = editCompositionState(); if (compositionState->sidebandStream.get() && !compositionState->sidebandStreamHasFrame) { - compositionState->compositionType = Hwc2::IComposerClient::Composition::SIDEBAND; + compositionState->compositionType = + aidl::android::hardware::graphics::composer3::Composition::SIDEBAND; return; } else { // Normal buffer layers compositionState->hdrMetadata = mBufferInfo.mHdrMetadata; compositionState->compositionType = mPotentialCursor - ? Hwc2::IComposerClient::Composition::CURSOR - : Hwc2::IComposerClient::Composition::DEVICE; + ? aidl::android::hardware::graphics::composer3::Composition::CURSOR + : aidl::android::hardware::graphics::composer3::Composition::DEVICE; } compositionState->buffer = mBufferInfo.mBuffer->getBuffer(); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 7e605f9d59..8bf7f8fbfa 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -39,6 +39,8 @@ #include "DisplayHardware/Hal.h" +#include + // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" @@ -156,7 +158,8 @@ struct LayerFECompositionState { */ // The type of composition for this layer - hal::Composition compositionType{hal::Composition::INVALID}; + aidl::android::hardware::graphics::composer3::Composition compositionType{ + aidl::android::hardware::graphics::composer3::Composition::INVALID}; // The buffer and related state sp buffer; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index ead941d1f9..a2824f5f9a 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -33,6 +33,8 @@ #include "LayerFE.h" +#include + // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" @@ -112,7 +114,8 @@ public: virtual bool isHardwareCursor() const = 0; // Applies a HWC device requested composition type change - virtual void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) = 0; + virtual void applyDeviceCompositionTypeChange( + aidl::android::hardware::graphics::composer3::Composition) = 0; // Prepares to apply any HWC device layer requests virtual void prepareForDeviceLayerRequests() = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index c15249d297..0082dac978 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -27,6 +27,8 @@ #include "DisplayHardware/DisplayIdentification.h" +#include + namespace android::compositionengine { struct LayerFECompositionState; @@ -50,7 +52,8 @@ public: HWC2::Layer* getHwcLayer() const override; bool requiresClientComposition() const override; bool isHardwareCursor() const override; - void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override; + void applyDeviceCompositionTypeChange( + aidl::android::hardware::graphics::composer3::Composition) override; void prepareForDeviceLayerRequests() override; void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override; bool needsFiltering() const override; @@ -68,21 +71,24 @@ protected: private: Rect calculateInitialCrop() const; - void writeOutputDependentGeometryStateToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition, - uint32_t z); + void writeOutputDependentGeometryStateToHWC( + HWC2::Layer*, aidl::android::hardware::graphics::composer3::Composition, uint32_t z); void writeOutputIndependentGeometryStateToHWC(HWC2::Layer*, const LayerFECompositionState&, bool skipLayer); void writeOutputDependentPerFrameStateToHWC(HWC2::Layer*); void writeOutputIndependentPerFrameStateToHWC( HWC2::Layer*, const LayerFECompositionState&, - Hwc2::IComposerClient::Composition compositionType, bool skipLayer); + aidl::android::hardware::graphics::composer3::Composition compositionType, + bool skipLayer); void writeSolidColorStateToHWC(HWC2::Layer*, const LayerFECompositionState&); void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&); void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&, bool skipLayer); - void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition, + void writeCompositionTypeToHWC(HWC2::Layer*, + aidl::android::hardware::graphics::composer3::Composition, bool isPeekingThrough, bool skipLayer); - void detectDisallowedCompositionTypeChange(Hwc2::IComposerClient::Composition from, - Hwc2::IComposerClient::Composition to) const; + void detectDisallowedCompositionTypeChange( + aidl::android::hardware::graphics::composer3::Composition from, + aidl::android::hardware::graphics::composer3::Composition to) const; bool isClientCompositionForced(bool isPeekingThrough) const; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index 627b80bcc2..49cb91291f 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -35,6 +35,8 @@ #include "DisplayHardware/ComposerHal.h" +#include + // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" @@ -123,8 +125,8 @@ struct OutputLayerCompositionState { std::shared_ptr hwcLayer; // The most recently set HWC composition type for this layer - Hwc2::IComposerClient::Composition hwcCompositionType{ - Hwc2::IComposerClient::Composition::INVALID}; + aidl::android::hardware::graphics::composer3::Composition hwcCompositionType{ + aidl::android::hardware::graphics::composer3::Composition::INVALID}; // The buffer cache for this layer. This is used to lower the // cost of sending reused buffers to the HWC. diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h index 7397c19837..14324de7ce 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h @@ -28,6 +28,8 @@ #include "DisplayHardware/Hal.h" #include "math/HashCombine.h" +#include + namespace std { template struct hash> { @@ -232,7 +234,7 @@ public: return mBackgroundBlurRadius.get() > 0 || !mBlurRegions.get().empty(); } int32_t getBackgroundBlurRadius() const { return mBackgroundBlurRadius.get(); } - hardware::graphics::composer::hal::Composition getCompositionType() const { + aidl::android::hardware::graphics::composer3::Composition getCompositionType() const { return mCompositionType.get(); } @@ -370,17 +372,18 @@ private: OutputLayerState mColorTransform; - using CompositionTypeState = OutputLayerState; - CompositionTypeState - mCompositionType{[](auto layer) { - return layer->getState().forceClientComposition - ? hardware::graphics::composer::hal::Composition::CLIENT - : layer->getLayerFE() - .getCompositionState() - ->compositionType; - }, - CompositionTypeState::getHalToStrings()}; + using CompositionTypeState = + OutputLayerState; + CompositionTypeState mCompositionType{[](auto layer) { + return layer->getState().forceClientComposition + ? aidl::android::hardware::graphics:: + composer3::Composition::CLIENT + : layer->getLayerFE() + .getCompositionState() + ->compositionType; + }, + CompositionTypeState::getHalToStrings()}; OutputLayerState mSidebandStream{[](auto layer) { diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h index fe486d3327..ef1560e23d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h @@ -109,7 +109,7 @@ public: static std::optional fromString(const std::string&); void reset() { mLayerTypes.clear(); } - void addLayerType(hardware::graphics::composer::hal::Composition type) { + void addLayerType(aidl::android::hardware::graphics::composer3::Composition type) { mLayerTypes.emplace_back(type); } @@ -125,7 +125,7 @@ public: } private: - std::vector mLayerTypes; + std::vector mLayerTypes; }; } // namespace android::compositionengine::impl::planner diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h index 358ed5a0b9..a6cb811468 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -46,7 +46,8 @@ public: MOCK_CONST_METHOD0(getHwcLayer, HWC2::Layer*()); MOCK_CONST_METHOD0(requiresClientComposition, bool()); MOCK_CONST_METHOD0(isHardwareCursor, bool()); - MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition)); + MOCK_METHOD1(applyDeviceCompositionTypeChange, + void(aidl::android::hardware::graphics::composer3::Composition)); MOCK_METHOD0(prepareForDeviceLayerRequests, void()); MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request)); MOCK_CONST_METHOD0(needsFiltering, bool()); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 4603e6bc3e..35713192e0 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -282,7 +282,8 @@ void Display::applyChangedTypesToLayers(const ChangedTypes& changedTypes) { if (auto it = changedTypes.find(hwcLayer); it != changedTypes.end()) { layer->applyDeviceCompositionTypeChange( - static_cast(it->second)); + static_cast( + it->second)); } } } diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index b010d9f965..e6bcec869e 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -37,6 +37,8 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" +using aidl::android::hardware::graphics::composer3::Composition; + namespace android::compositionengine { OutputLayer::~OutputLayer() = default; @@ -358,8 +360,8 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t auto requestedCompositionType = outputIndependentState->compositionType; - if (requestedCompositionType == hal::Composition::SOLID_COLOR && state.overrideInfo.buffer) { - requestedCompositionType = hal::Composition::DEVICE; + if (requestedCompositionType == Composition::SOLID_COLOR && state.overrideInfo.buffer) { + requestedCompositionType = Composition::DEVICE; } // TODO(b/181172795): We now update geometry for all flattened layers. We should update it @@ -380,7 +382,7 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough, skipLayer); - if (requestedCompositionType == hal::Composition::SOLID_COLOR) { + if (requestedCompositionType == Composition::SOLID_COLOR) { writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState); } @@ -389,7 +391,7 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t } void OutputLayer::writeOutputDependentGeometryStateToHWC(HWC2::Layer* hwcLayer, - hal::Composition requestedCompositionType, + Composition requestedCompositionType, uint32_t z) { const auto& outputDependentState = getState(); @@ -423,7 +425,7 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC(HWC2::Layer* hwcLayer, } // Solid-color layers and overridden buffers should always use an identity transform. - const auto bufferTransform = (requestedCompositionType != hal::Composition::SOLID_COLOR && + const auto bufferTransform = (requestedCompositionType != Composition::SOLID_COLOR && getState().overrideInfo.buffer == nullptr) ? outputDependentState.bufferTransform : static_cast(0); @@ -504,7 +506,7 @@ void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) void OutputLayer::writeOutputIndependentPerFrameStateToHWC( HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState, - hal::Composition compositionType, bool skipLayer) { + Composition compositionType, bool skipLayer) { switch (auto error = hwcLayer->setColorTransform(outputIndependentState.colorTransform)) { case hal::Error::NONE: break; @@ -529,18 +531,18 @@ void OutputLayer::writeOutputIndependentPerFrameStateToHWC( // Content-specific per-frame state switch (compositionType) { - case hal::Composition::SOLID_COLOR: + case Composition::SOLID_COLOR: // For compatibility, should be written AFTER the composition type. break; - case hal::Composition::SIDEBAND: + case Composition::SIDEBAND: writeSidebandStateToHWC(hwcLayer, outputIndependentState); break; - case hal::Composition::CURSOR: - case hal::Composition::DEVICE: + case Composition::CURSOR: + case Composition::DEVICE: writeBufferStateToHWC(hwcLayer, outputIndependentState, skipLayer); break; - case hal::Composition::INVALID: - case hal::Composition::CLIENT: + case Composition::INVALID: + case Composition::CLIENT: // Ignored break; } @@ -606,13 +608,13 @@ void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer, } void OutputLayer::writeCompositionTypeToHWC(HWC2::Layer* hwcLayer, - hal::Composition requestedCompositionType, + Composition requestedCompositionType, bool isPeekingThrough, bool skipLayer) { auto& outputDependentState = editState(); if (isClientCompositionForced(isPeekingThrough)) { // If we are forcing client composition, we need to tell the HWC - requestedCompositionType = hal::Composition::CLIENT; + requestedCompositionType = Composition::CLIENT; } // Set the requested composition type with the HWC whenever it changes @@ -625,7 +627,7 @@ void OutputLayer::writeCompositionTypeToHWC(HWC2::Layer* hwcLayer, if (auto error = hwcLayer->setCompositionType(requestedCompositionType); error != hal::Error::NONE) { ALOGE("[%s] Failed to set composition type %s: %s (%d)", getLayerFE().getDebugName(), - toString(requestedCompositionType).c_str(), to_string(error).c_str(), + to_string(requestedCompositionType).c_str(), to_string(error).c_str(), static_cast(error)); } } @@ -664,38 +666,37 @@ HWC2::Layer* OutputLayer::getHwcLayer() const { bool OutputLayer::requiresClientComposition() const { const auto& state = getState(); - return !state.hwc || state.hwc->hwcCompositionType == hal::Composition::CLIENT; + return !state.hwc || state.hwc->hwcCompositionType == Composition::CLIENT; } bool OutputLayer::isHardwareCursor() const { const auto& state = getState(); - return state.hwc && state.hwc->hwcCompositionType == hal::Composition::CURSOR; + return state.hwc && state.hwc->hwcCompositionType == Composition::CURSOR; } -void OutputLayer::detectDisallowedCompositionTypeChange(hal::Composition from, - hal::Composition to) const { +void OutputLayer::detectDisallowedCompositionTypeChange(Composition from, Composition to) const { bool result = false; switch (from) { - case hal::Composition::INVALID: - case hal::Composition::CLIENT: + case Composition::INVALID: + case Composition::CLIENT: result = false; break; - case hal::Composition::DEVICE: - case hal::Composition::SOLID_COLOR: - result = (to == hal::Composition::CLIENT); + case Composition::DEVICE: + case Composition::SOLID_COLOR: + result = (to == Composition::CLIENT); break; - case hal::Composition::CURSOR: - case hal::Composition::SIDEBAND: - result = (to == hal::Composition::CLIENT || to == hal::Composition::DEVICE); + case Composition::CURSOR: + case Composition::SIDEBAND: + result = (to == Composition::CLIENT || to == Composition::DEVICE); break; } if (!result) { ALOGE("[%s] Invalid device requested composition type change: %s (%d) --> %s (%d)", - getLayerFE().getDebugName(), toString(from).c_str(), static_cast(from), - toString(to).c_str(), static_cast(to)); + getLayerFE().getDebugName(), to_string(from).c_str(), static_cast(from), + to_string(to).c_str(), static_cast(to)); } } @@ -704,7 +705,7 @@ bool OutputLayer::isClientCompositionForced(bool isPeekingThrough) const { (!isPeekingThrough && getLayerFE().hasRoundedCorners()); } -void OutputLayer::applyDeviceCompositionTypeChange(hal::Composition compositionType) { +void OutputLayer::applyDeviceCompositionTypeChange(Composition compositionType) { auto& state = editState(); LOG_FATAL_IF(!state.hwc); auto& hwcState = *state.hwc; diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp index c14effccc3..0918510eef 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp @@ -211,7 +211,8 @@ size_t Flattener::calculateDisplayCost(const std::vector& lay displayCost += static_cast(layer->getDisplayFrame().width() * layer->getDisplayFrame().height()); - hasClientComposition |= layer->getCompositionType() == hal::Composition::CLIENT; + hasClientComposition |= layer->getCompositionType() == + aidl::android::hardware::graphics::composer3::Composition::CLIENT; } if (hasClientComposition) { diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp index 2532e3df5d..c79ca0d959 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp @@ -160,7 +160,8 @@ bool operator==(const LayerState& lhs, const LayerState& rhs) { lhs.mColorTransform == rhs.mColorTransform && lhs.mCompositionType == rhs.mCompositionType && lhs.mSidebandStream == rhs.mSidebandStream && lhs.mBuffer == rhs.mBuffer && - (lhs.mCompositionType.get() != hal::Composition::SOLID_COLOR || + (lhs.mCompositionType.get() != + aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR || lhs.mSolidColor == rhs.mSolidColor); } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp index f5b1cee469..74d27015d7 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp @@ -193,7 +193,7 @@ void Planner::reportFinalPlan( finalPlan.addLayerType( forcedOrRequestedClient - ? hardware::graphics::composer::hal::Composition::CLIENT + ? aidl::android::hardware::graphics::composer3::Composition::CLIENT : layer->getLayerFE().getCompositionState()->compositionType); } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp index 8226ef7b4c..074673e550 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp @@ -39,8 +39,10 @@ std::optional LayerStack::getApproximateMatch( // Skip layers where both are client-composited, since that doesn't change the // composition plan - if (mLayers[i].getCompositionType() == hal::Composition::CLIENT && - other[i]->getCompositionType() == hal::Composition::CLIENT) { + if (mLayers[i].getCompositionType() == + aidl::android::hardware::graphics::composer3::Composition::CLIENT && + other[i]->getCompositionType() == + aidl::android::hardware::graphics::composer3::Composition::CLIENT) { continue; } @@ -89,22 +91,28 @@ std::optional Plan::fromString(const std::string& string) { for (char c : string) { switch (c) { case 'C': - plan.addLayerType(hal::Composition::CLIENT); + plan.addLayerType( + aidl::android::hardware::graphics::composer3::Composition::CLIENT); continue; case 'U': - plan.addLayerType(hal::Composition::CURSOR); + plan.addLayerType( + aidl::android::hardware::graphics::composer3::Composition::CURSOR); continue; case 'D': - plan.addLayerType(hal::Composition::DEVICE); + plan.addLayerType( + aidl::android::hardware::graphics::composer3::Composition::DEVICE); continue; case 'I': - plan.addLayerType(hal::Composition::INVALID); + plan.addLayerType( + aidl::android::hardware::graphics::composer3::Composition::INVALID); continue; case 'B': - plan.addLayerType(hal::Composition::SIDEBAND); + plan.addLayerType( + aidl::android::hardware::graphics::composer3::Composition::SIDEBAND); continue; case 'S': - plan.addLayerType(hal::Composition::SOLID_COLOR); + plan.addLayerType( + aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR); continue; default: return std::nullopt; @@ -117,22 +125,22 @@ std::string to_string(const Plan& plan) { std::string result; for (auto type : plan.mLayerTypes) { switch (type) { - case hal::Composition::CLIENT: + case aidl::android::hardware::graphics::composer3::Composition::CLIENT: result.append("C"); break; - case hal::Composition::CURSOR: + case aidl::android::hardware::graphics::composer3::Composition::CURSOR: result.append("U"); break; - case hal::Composition::DEVICE: + case aidl::android::hardware::graphics::composer3::Composition::DEVICE: result.append("D"); break; - case hal::Composition::INVALID: + case aidl::android::hardware::graphics::composer3::Composition::INVALID: result.append("I"); break; - case hal::Composition::SIDEBAND: + case aidl::android::hardware::graphics::composer3::Composition::SIDEBAND: result.append("B"); break; - case hal::Composition::SOLID_COLOR: + case aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR: result.append("S"); break; } diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 568efce8b3..3bdb2c03d1 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -38,6 +38,10 @@ #include "MockHWComposer.h" #include "MockPowerAdvisor.h" +#include + +using aidl::android::hardware::graphics::composer3::Composition; + namespace android::compositionengine { namespace { @@ -592,7 +596,7 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { android::HWComposer::DeviceRequestedChanges changes{ - {{nullptr, hal::Composition::CLIENT}}, + {{nullptr, Composition::CLIENT}}, hal::DisplayRequest::FLIP_CLIENT_TARGET, {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}}, {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN}, @@ -700,17 +704,15 @@ TEST_F(DisplayApplyChangedTypesToLayersTest, takesEarlyOutIfNoChangedLayers) { } TEST_F(DisplayApplyChangedTypesToLayersTest, appliesChanges) { - EXPECT_CALL(*mLayer1.outputLayer, - applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT)) + EXPECT_CALL(*mLayer1.outputLayer, applyDeviceCompositionTypeChange(Composition::CLIENT)) .Times(1); - EXPECT_CALL(*mLayer2.outputLayer, - applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::DEVICE)) + EXPECT_CALL(*mLayer2.outputLayer, applyDeviceCompositionTypeChange(Composition::DEVICE)) .Times(1); mDisplay->applyChangedTypesToLayers(impl::Display::ChangedTypes{ - {&mLayer1.hwc2Layer, hal::Composition::CLIENT}, - {&mLayer2.hwc2Layer, hal::Composition::DEVICE}, - {&hwc2LayerUnknown, hal::Composition::SOLID_COLOR}, + {&mLayer1.hwc2Layer, Composition::CLIENT}, + {&mLayer2.hwc2Layer, Composition::DEVICE}, + {&hwc2LayerUnknown, Composition::SOLID_COLOR}, }); } diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h index 9e08f9eddc..ff680533ea 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h @@ -32,6 +32,8 @@ #include #include "DisplayHardware/HWC2.h" +#include + // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" @@ -57,7 +59,8 @@ public: MOCK_METHOD1(setSurfaceDamage, Error(const android::Region&)); MOCK_METHOD1(setBlendMode, Error(hal::BlendMode)); MOCK_METHOD1(setColor, Error(hal::Color)); - MOCK_METHOD1(setCompositionType, Error(hal::Composition)); + MOCK_METHOD1(setCompositionType, + Error(aidl::android::hardware::graphics::composer3::Composition)); MOCK_METHOD1(setDataspace, Error(android::ui::Dataspace)); MOCK_METHOD2(setPerFrameMetadata, Error(const int32_t, const android::HdrMetadata&)); MOCK_METHOD1(setDisplayFrame, Error(const android::Rect&)); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 207c31e756..ad7976f64c 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -30,6 +30,10 @@ #include "MockHWComposer.h" #include "RegionMatcher.h" +#include + +using aidl::android::hardware::graphics::composer3::Composition; + namespace android::compositionengine { namespace { @@ -851,7 +855,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { EXPECT_CALL(*mHwcLayer, setSurfaceDamage(RegionEq(surfaceDamage))).WillOnce(Return(kError)); } - void expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition compositionType) { + void expectSetCompositionTypeCall(Composition compositionType) { EXPECT_CALL(*mHwcLayer, setCompositionType(compositionType)).WillOnce(Return(kError)); } @@ -975,7 +979,7 @@ TEST_F(OutputLayerTest, displayInstallOrientationBufferTransformSetTo90) { } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; + mLayerFEState.compositionType = Composition::SOLID_COLOR; expectPerFrameCommonCalls(); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); @@ -984,7 +988,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) { // check this in this test only by setting up an testing::InSeqeuence // instance before setting up the two expectations. InSequence s; - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SOLID_COLOR); + expectSetCompositionTypeCall(Composition::SOLID_COLOR); expectSetColorCall(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, @@ -992,11 +996,11 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) { } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND; + mLayerFEState.compositionType = Composition::SIDEBAND; expectPerFrameCommonCalls(); expectSetSidebandHandleCall(); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SIDEBAND); + expectSetCompositionTypeCall(Composition::SIDEBAND); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); @@ -1005,11 +1009,11 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) { } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::CURSOR; + mLayerFEState.compositionType = Composition::CURSOR; expectPerFrameCommonCalls(); expectSetHdrMetadataAndBufferCalls(); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CURSOR); + expectSetCompositionTypeCall(Composition::CURSOR); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); @@ -1018,11 +1022,11 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) { } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + mLayerFEState.compositionType = Composition::DEVICE; expectPerFrameCommonCalls(); expectSetHdrMetadataAndBufferCalls(); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + expectSetCompositionTypeCall(Composition::DEVICE); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); @@ -1031,10 +1035,9 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) { } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) { - (*mOutputLayer.editState().hwc).hwcCompositionType = - Hwc2::IComposerClient::Composition::SOLID_COLOR; + (*mOutputLayer.editState().hwc).hwcCompositionType = Composition::SOLID_COLOR; - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; + mLayerFEState.compositionType = Composition::SOLID_COLOR; expectPerFrameCommonCalls(); expectSetColorCall(); @@ -1047,11 +1050,11 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) { } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransformNotSupported) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; + mLayerFEState.compositionType = Composition::SOLID_COLOR; expectPerFrameCommonCalls(SimulateUnsupported::ColorTransform); expectSetColorCall(); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT); + expectSetCompositionTypeCall(Composition::CLIENT); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, /*zIsOverridden*/ false, /*isPeekingThrough*/ false); @@ -1060,25 +1063,25 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransf TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompositionForced) { mOutputLayer.editState().forceClientComposition = true; - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; + mLayerFEState.compositionType = Composition::SOLID_COLOR; expectPerFrameCommonCalls(); expectSetColorCall(); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT); + expectSetCompositionTypeCall(Composition::CLIENT); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + mLayerFEState.compositionType = Composition::DEVICE; includeGenericLayerMetadataInState(); expectGeometryCommonCalls(); expectPerFrameCommonCalls(); expectSetHdrMetadataAndBufferCalls(); expectGenericLayerMetadataCalls(); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + expectSetCompositionTypeCall(Composition::DEVICE); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); @@ -1087,12 +1090,12 @@ TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) { } TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPresent) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + mLayerFEState.compositionType = Composition::DEVICE; includeGenericLayerMetadataInState(); expectPerFrameCommonCalls(); expectSetHdrMetadataAndBufferCalls(); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + expectSetCompositionTypeCall(Composition::DEVICE); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); @@ -1101,7 +1104,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPres } TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerDoesNotSendBuffer) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + mLayerFEState.compositionType = Composition::DEVICE; includeOverrideInfo(); expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform, @@ -1109,7 +1112,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerDoesNotSendBuffer) { expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion, kOverrideSurfaceDamage, kDisplayBrightnessNits); expectSetHdrMetadataAndBufferCalls(); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + expectSetCompositionTypeCall(Composition::DEVICE); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, 0, @@ -1117,7 +1120,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerDoesNotSendBuffer) { } TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerForSolidColorDoesNotSendBuffer) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; + mLayerFEState.compositionType = Composition::SOLID_COLOR; includeOverrideInfo(); expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform, @@ -1125,7 +1128,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerForSolidColorDoesNotSe expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion, kOverrideSurfaceDamage, kDisplayBrightnessNits); expectSetHdrMetadataAndBufferCalls(); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + expectSetCompositionTypeCall(Composition::DEVICE); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, 0, @@ -1133,7 +1136,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerForSolidColorDoesNotSe } TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + mLayerFEState.compositionType = Composition::DEVICE; includeOverrideInfo(); expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform, @@ -1141,7 +1144,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion, kOverrideSurfaceDamage, kDisplayBrightnessNits); expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + expectSetCompositionTypeCall(Composition::DEVICE); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, @@ -1149,7 +1152,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { } TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoForSolidColorIfPresent) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; + mLayerFEState.compositionType = Composition::SOLID_COLOR; includeOverrideInfo(); expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform, @@ -1157,7 +1160,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoForSolidColorIfPresen expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion, kOverrideSurfaceDamage, kDisplayBrightnessNits); expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + expectSetCompositionTypeCall(Composition::DEVICE); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, @@ -1165,14 +1168,14 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoForSolidColorIfPresen } TEST_F(OutputLayerWriteStateToHWCTest, previousOverriddenLayerSendsSurfaceDamage) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + mLayerFEState.compositionType = Composition::DEVICE; mOutputLayer.editState().hwc->stateOverridden = true; expectGeometryCommonCalls(); expectPerFrameCommonCalls(SimulateUnsupported::None, kDataspace, kOutputSpaceVisibleRegion, Region::INVALID_REGION); expectSetHdrMetadataAndBufferCalls(); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + expectSetCompositionTypeCall(Composition::DEVICE); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, @@ -1180,16 +1183,16 @@ TEST_F(OutputLayerWriteStateToHWCTest, previousOverriddenLayerSendsSurfaceDamage } TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedDeviceCompositionInfo) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + mLayerFEState.compositionType = Composition::DEVICE; mOutputLayer.editState().hwc->stateOverridden = true; mOutputLayer.editState().hwc->layerSkipped = true; - mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE; + mOutputLayer.editState().hwc->hwcCompositionType = Composition::DEVICE; expectGeometryCommonCalls(); expectPerFrameCommonCalls(SimulateUnsupported::None, kDataspace, kOutputSpaceVisibleRegion, Region::INVALID_REGION); expectSetHdrMetadataAndBufferCalls(); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + expectSetCompositionTypeCall(Composition::DEVICE); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, @@ -1197,17 +1200,17 @@ TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedDeviceCompos } TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedClientCompositionInfo) { - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + mLayerFEState.compositionType = Composition::DEVICE; mOutputLayer.editState().forceClientComposition = true; mOutputLayer.editState().hwc->stateOverridden = true; mOutputLayer.editState().hwc->layerSkipped = true; - mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CLIENT; + mOutputLayer.editState().hwc->hwcCompositionType = Composition::CLIENT; expectGeometryCommonCalls(); expectPerFrameCommonCalls(SimulateUnsupported::None, kDataspace, kOutputSpaceVisibleRegion, Region::INVALID_REGION); expectSetHdrMetadataAndBufferCalls(); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT); + expectSetCompositionTypeCall(Composition::CLIENT); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, @@ -1253,7 +1256,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, roundedCornersForceClientComposition) { expectGeometryCommonCalls(); expectPerFrameCommonCalls(); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(true)); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT); + expectSetCompositionTypeCall(Composition::CLIENT); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, /*zIsOverridden*/ false, /*isPeekingThrough*/ @@ -1265,14 +1268,13 @@ TEST_F(OutputLayerWriteStateToHWCTest, roundedCornersPeekingThroughAllowsDeviceC expectPerFrameCommonCalls(); expectSetHdrMetadataAndBufferCalls(); EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(true)); - expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); + expectSetCompositionTypeCall(Composition::DEVICE); - mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE; + mLayerFEState.compositionType = Composition::DEVICE; mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, /*zIsOverridden*/ false, /*isPeekingThrough*/ true); - EXPECT_EQ(Hwc2::IComposerClient::Composition::DEVICE, - mOutputLayer.getState().hwc->hwcCompositionType); + EXPECT_EQ(Composition::DEVICE, mOutputLayer.getState().hwc->hwcCompositionType); } /* @@ -1371,14 +1373,14 @@ TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfNoHWC2State) { TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfSetToClientComposition) { mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr}; - mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CLIENT; + mOutputLayer.editState().hwc->hwcCompositionType = Composition::CLIENT; EXPECT_TRUE(mOutputLayer.requiresClientComposition()); } TEST_F(OutputLayerTest, requiresClientCompositionReturnsFalseIfSetToDeviceComposition) { mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr}; - mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE; + mOutputLayer.editState().hwc->hwcCompositionType = Composition::DEVICE; EXPECT_FALSE(mOutputLayer.requiresClientComposition()); } @@ -1395,14 +1397,14 @@ TEST_F(OutputLayerTest, isHardwareCursorReturnsFalseIfNoHWC2State) { TEST_F(OutputLayerTest, isHardwareCursorReturnsTrueIfSetToCursorComposition) { mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr}; - mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CURSOR; + mOutputLayer.editState().hwc->hwcCompositionType = Composition::CURSOR; EXPECT_TRUE(mOutputLayer.isHardwareCursor()); } TEST_F(OutputLayerTest, isHardwareCursorReturnsFalseIfSetToDeviceComposition) { mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr}; - mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE; + mOutputLayer.editState().hwc->hwcCompositionType = Composition::DEVICE; EXPECT_FALSE(mOutputLayer.isHardwareCursor()); } @@ -1413,13 +1415,12 @@ TEST_F(OutputLayerTest, isHardwareCursorReturnsFalseIfSetToDeviceComposition) { TEST_F(OutputLayerTest, applyDeviceCompositionTypeChangeSetsNewType) { mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr}; - mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE; + mOutputLayer.editState().hwc->hwcCompositionType = Composition::DEVICE; - mOutputLayer.applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT); + mOutputLayer.applyDeviceCompositionTypeChange(Composition::CLIENT); ASSERT_TRUE(mOutputLayer.getState().hwc); - EXPECT_EQ(Hwc2::IComposerClient::Composition::CLIENT, - mOutputLayer.getState().hwc->hwcCompositionType); + EXPECT_EQ(Composition::CLIENT, mOutputLayer.getState().hwc->hwcCompositionType); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp index 9ad3ab4057..84b3fc5698 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp @@ -27,6 +27,10 @@ #include "android/hardware_buffer.h" #include "compositionengine/LayerFECompositionState.h" +#include + +using aidl::android::hardware::graphics::composer3::Composition; + namespace android::compositionengine::impl::planner { namespace { @@ -277,33 +281,28 @@ TEST_F(LayerStateTest, compareDisplayFrame) { TEST_F(LayerStateTest, getCompositionType) { OutputLayerCompositionState outputLayerCompositionState; LayerFECompositionState layerFECompositionState; - layerFECompositionState.compositionType = - hardware::graphics::composer::hal::Composition::DEVICE; + layerFECompositionState.compositionType = Composition::DEVICE; setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, layerFECompositionState); mLayerState = std::make_unique(&mOutputLayer); - EXPECT_EQ(hardware::graphics::composer::hal::Composition::DEVICE, - mLayerState->getCompositionType()); + EXPECT_EQ(Composition::DEVICE, mLayerState->getCompositionType()); } TEST_F(LayerStateTest, getCompositionType_forcedClient) { OutputLayerCompositionState outputLayerCompositionState; outputLayerCompositionState.forceClientComposition = true; LayerFECompositionState layerFECompositionState; - layerFECompositionState.compositionType = - hardware::graphics::composer::hal::Composition::DEVICE; + layerFECompositionState.compositionType = Composition::DEVICE; setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, layerFECompositionState); mLayerState = std::make_unique(&mOutputLayer); - EXPECT_EQ(hardware::graphics::composer::hal::Composition::CLIENT, - mLayerState->getCompositionType()); + EXPECT_EQ(Composition::CLIENT, mLayerState->getCompositionType()); } TEST_F(LayerStateTest, updateCompositionType) { OutputLayerCompositionState outputLayerCompositionState; LayerFECompositionState layerFECompositionState; - layerFECompositionState.compositionType = - hardware::graphics::composer::hal::Composition::DEVICE; + layerFECompositionState.compositionType = Composition::DEVICE; setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, layerFECompositionState); mLayerState = std::make_unique(&mOutputLayer); @@ -311,29 +310,25 @@ TEST_F(LayerStateTest, updateCompositionType) { mock::OutputLayer newOutputLayer; mock::LayerFE newLayerFE; LayerFECompositionState layerFECompositionStateTwo; - layerFECompositionStateTwo.compositionType = - hardware::graphics::composer::hal::Composition::SOLID_COLOR; + layerFECompositionStateTwo.compositionType = Composition::SOLID_COLOR; setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(hardware::graphics::composer::hal::Composition::SOLID_COLOR, - mLayerState->getCompositionType()); + EXPECT_EQ(Composition::SOLID_COLOR, mLayerState->getCompositionType()); EXPECT_EQ(Flags(LayerStateField::CompositionType), updates); } TEST_F(LayerStateTest, compareCompositionType) { OutputLayerCompositionState outputLayerCompositionState; LayerFECompositionState layerFECompositionState; - layerFECompositionState.compositionType = - hardware::graphics::composer::hal::Composition::DEVICE; + layerFECompositionState.compositionType = Composition::DEVICE; setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, layerFECompositionState); mLayerState = std::make_unique(&mOutputLayer); mock::OutputLayer newOutputLayer; mock::LayerFE newLayerFE; LayerFECompositionState layerFECompositionStateTwo; - layerFECompositionStateTwo.compositionType = - hardware::graphics::composer::hal::Composition::SOLID_COLOR; + layerFECompositionStateTwo.compositionType = Composition::SOLID_COLOR; setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); auto otherLayerState = std::make_unique(&newOutputLayer); diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp index 1492707ad2..6038268a8c 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp @@ -24,6 +24,10 @@ #include #include +#include + +using aidl::android::hardware::graphics::composer3::Composition; + namespace android::compositionengine::impl::planner { namespace { @@ -103,7 +107,7 @@ TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchDifferentCompositionTypes mock::LayerFE layerFEOne; OutputLayerCompositionState outputLayerCompositionStateOne; LayerFECompositionState layerFECompositionStateOne; - layerFECompositionStateOne.compositionType = hal::Composition::DEVICE; + layerFECompositionStateOne.compositionType = Composition::DEVICE; setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne, layerFECompositionStateOne); LayerState layerStateOne(&outputLayerOne); @@ -112,7 +116,7 @@ TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchDifferentCompositionTypes mock::LayerFE layerFETwo; OutputLayerCompositionState outputLayerCompositionStateTwo; LayerFECompositionState layerFECompositionStateTwo; - layerFECompositionStateTwo.compositionType = hal::Composition::SOLID_COLOR; + layerFECompositionStateTwo.compositionType = Composition::SOLID_COLOR; setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo, layerFECompositionStateTwo); LayerState layerStateTwo(&outputLayerTwo); @@ -370,7 +374,7 @@ TEST_F(LayerStackTest, reorderingChangesNonBufferHash) { TEST_F(PredictionTest, constructPrediction) { Plan plan; - plan.addLayerType(hal::Composition::DEVICE); + plan.addLayerType(Composition::DEVICE); Prediction prediction({}, plan); @@ -442,13 +446,13 @@ TEST_F(PredictorTest, getPredictedPlan_recordCandidateAndRetrieveExactMatch) { mock::LayerFE layerFEOne; OutputLayerCompositionState outputLayerCompositionStateOne; LayerFECompositionState layerFECompositionStateOne; - layerFECompositionStateOne.compositionType = hal::Composition::DEVICE; + layerFECompositionStateOne.compositionType = Composition::DEVICE; setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne, layerFECompositionStateOne); LayerState layerStateOne(&outputLayerOne); Plan plan; - plan.addLayerType(hal::Composition::DEVICE); + plan.addLayerType(Composition::DEVICE); Predictor predictor; @@ -484,7 +488,7 @@ TEST_F(PredictorTest, getPredictedPlan_recordCandidateAndRetrieveApproximateMatc LayerState layerStateTwo(&outputLayerTwo); Plan plan; - plan.addLayerType(hal::Composition::DEVICE); + plan.addLayerType(Composition::DEVICE); Predictor predictor; @@ -521,7 +525,7 @@ TEST_F(PredictorTest, recordMissedPlan_skipsApproximateMatch) { LayerState layerStateTwo(&outputLayerTwo); Plan plan; - plan.addLayerType(hal::Composition::DEVICE); + plan.addLayerType(Composition::DEVICE); Predictor predictor; @@ -535,7 +539,7 @@ TEST_F(PredictorTest, recordMissedPlan_skipsApproximateMatch) { EXPECT_EQ(Prediction::Type::Approximate, predictedPlan->type); Plan planTwo; - planTwo.addLayerType(hal::Composition::CLIENT); + planTwo.addLayerType(Composition::CLIENT); predictor.recordResult(predictedPlan, hashTwo, {&layerStateTwo}, false, planTwo); // Now trying to retrieve the predicted plan again returns a nullopt instead. // TODO(b/158790260): Even though this is enforced in this test, we might want to reassess this. diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index 29e5a7464d..87635797be 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -375,13 +375,11 @@ Error AidlComposer::getActiveConfig(Display display, Config* outConfig) { Error AidlComposer::getChangedCompositionTypes( Display display, std::vector* outLayers, - std::vector* outTypes) { + std::vector* outTypes) { std::vector layers; - std::vector types; - mReader.takeChangedCompositionTypes(translate(display), &layers, &types); + mReader.takeChangedCompositionTypes(translate(display), &layers, outTypes); *outLayers = translate(layers); - *outTypes = translate(types); return Error::NONE; } @@ -649,10 +647,10 @@ Error AidlComposer::setLayerColor(Display display, Layer layer, return Error::NONE; } -Error AidlComposer::setLayerCompositionType(Display display, Layer layer, - IComposerClient::Composition type) { - mWriter.setLayerCompositionType(translate(display), translate(layer), - translate(type)); +Error AidlComposer::setLayerCompositionType( + Display display, Layer layer, + aidl::android::hardware::graphics::composer3::Composition type) { + mWriter.setLayerCompositionType(translate(display), translate(layer), type); return Error::NONE; } diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index 8cae25f742..d82d815cda 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -36,6 +36,8 @@ #include #include +#include + // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" @@ -78,8 +80,10 @@ public: Error destroyLayer(Display display, Layer layer) override; Error getActiveConfig(Display display, Config* outConfig) override; - Error getChangedCompositionTypes(Display display, std::vector* outLayers, - std::vector* outTypes) override; + Error getChangedCompositionTypes( + Display display, std::vector* outLayers, + std::vector* outTypes) + override; Error getColorModes(Display display, std::vector* outModes) override; Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) override; @@ -132,8 +136,9 @@ public: const std::vector& damage) override; Error setLayerBlendMode(Display display, Layer layer, IComposerClient::BlendMode mode) override; Error setLayerColor(Display display, Layer layer, const IComposerClient::Color& color) override; - Error setLayerCompositionType(Display display, Layer layer, - IComposerClient::Composition type) override; + Error setLayerCompositionType( + Display display, Layer layer, + aidl::android::hardware::graphics::composer3::Composition type) override; Error setLayerDataspace(Display display, Layer layer, Dataspace dataspace) override; Error setLayerDisplayFrame(Display display, Layer layer, const IComposerClient::Rect& frame) override; diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 3cc5e5e360..b4ba8abac7 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -31,6 +31,8 @@ #include #include +#include + // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" @@ -98,7 +100,7 @@ public: virtual Error getActiveConfig(Display display, Config* outConfig) = 0; virtual Error getChangedCompositionTypes( Display display, std::vector* outLayers, - std::vector* outTypes) = 0; + std::vector* outTypes) = 0; virtual Error getColorModes(Display display, std::vector* outModes) = 0; virtual Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) = 0; @@ -155,8 +157,9 @@ public: IComposerClient::BlendMode mode) = 0; virtual Error setLayerColor(Display display, Layer layer, const IComposerClient::Color& color) = 0; - virtual Error setLayerCompositionType(Display display, Layer layer, - IComposerClient::Composition type) = 0; + virtual Error setLayerCompositionType( + Display display, Layer layer, + aidl::android::hardware::graphics::composer3::Composition type) = 0; virtual Error setLayerDataspace(Display display, Layer layer, Dataspace dataspace) = 0; virtual Error setLayerDisplayFrame(Display display, Layer layer, const IComposerClient::Rect& frame) = 0; diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 596666c3f7..82f463eafa 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -39,6 +39,8 @@ #include "ComposerHal.h" +using aidl::android::hardware::graphics::composer3::Composition; + namespace android { using android::Fence; @@ -147,7 +149,7 @@ bool Display::isVsyncPeriodSwitchSupported() const { Error Display::getChangedCompositionTypes(std::unordered_map* outTypes) { std::vector layerIds; - std::vector types; + std::vector types; auto intError = mComposer.getChangedCompositionTypes( mId, &layerIds, &types); uint32_t numElements = layerIds.size(); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 5e0ba06a0e..1425c61b00 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -36,6 +36,8 @@ #include "Hal.h" +#include + namespace android { class Fence; @@ -88,7 +90,8 @@ public: [[clang::warn_unused_result]] virtual base::expected, hal::Error> createLayer() = 0; [[clang::warn_unused_result]] virtual hal::Error getChangedCompositionTypes( - std::unordered_map* outTypes) = 0; + std::unordered_map* + outTypes) = 0; [[clang::warn_unused_result]] virtual hal::Error getColorModes( std::vector* outModes) const = 0; // Returns a bitmask which contains HdrMetadata::Type::*. @@ -163,7 +166,9 @@ public: hal::Error acceptChanges() override; base::expected, hal::Error> createLayer() override; hal::Error getChangedCompositionTypes( - std::unordered_map* outTypes) override; + std::unordered_map* outTypes) + override; hal::Error getColorModes(std::vector* outModes) const override; // Returns a bitmask which contains HdrMetadata::Type::*. int32_t getSupportedPerFrameMetadata() const override; @@ -266,7 +271,8 @@ public: [[clang::warn_unused_result]] virtual hal::Error setBlendMode(hal::BlendMode mode) = 0; [[clang::warn_unused_result]] virtual hal::Error setColor(hal::Color color) = 0; - [[clang::warn_unused_result]] virtual hal::Error setCompositionType(hal::Composition type) = 0; + [[clang::warn_unused_result]] virtual hal::Error setCompositionType( + aidl::android::hardware::graphics::composer3::Composition type) = 0; [[clang::warn_unused_result]] virtual hal::Error setDataspace(hal::Dataspace dataspace) = 0; [[clang::warn_unused_result]] virtual hal::Error setPerFrameMetadata( const int32_t supportedPerFrameMetadata, const android::HdrMetadata& metadata) = 0; @@ -316,7 +322,8 @@ public: hal::Error setBlendMode(hal::BlendMode mode) override; hal::Error setColor(hal::Color color) override; - hal::Error setCompositionType(hal::Composition type) override; + hal::Error setCompositionType( + aidl::android::hardware::graphics::composer3::Composition type) override; hal::Error setDataspace(hal::Dataspace dataspace) override; hal::Error setPerFrameMetadata(const int32_t supportedPerFrameMetadata, const android::HdrMetadata& metadata) override; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index bd79977bc9..aa4abdff48 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -43,6 +43,8 @@ #include "HWC2.h" #include "Hal.h" +#include + namespace android { namespace hal = hardware::graphics::composer::hal; @@ -70,7 +72,9 @@ struct KnownHWCGenericLayerMetadata { class HWComposer { public: struct DeviceRequestedChanges { - using ChangedTypes = std::unordered_map; + using ChangedTypes = + std::unordered_map; using ClientTargetProperty = hal::ClientTargetProperty; using DisplayRequests = hal::DisplayRequest; using LayerRequests = std::unordered_map; diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h index 02d065881b..77e704fa03 100644 --- a/services/surfaceflinger/DisplayHardware/Hal.h +++ b/services/surfaceflinger/DisplayHardware/Hal.h @@ -20,6 +20,8 @@ #include #include +#include + #define ERROR_HAS_CHANGES 5 namespace android { @@ -49,7 +51,6 @@ using V2_4::VsyncPeriodNanos; using Attribute = IComposerClient::Attribute; using BlendMode = IComposerClient::BlendMode; using Color = IComposerClient::Color; -using Composition = IComposerClient::Composition; using Connection = IComposerCallback::Connection; using ContentType = IComposerClient::ContentType; using Capability = IComposer::Capability; @@ -95,19 +96,20 @@ inline std::string to_string(hardware::graphics::composer::hal::Attribute attrib } } -inline std::string to_string(hardware::graphics::composer::hal::Composition composition) { +inline std::string to_string( + aidl::android::hardware::graphics::composer3::Composition composition) { switch (composition) { - case hardware::graphics::composer::hal::Composition::INVALID: + case aidl::android::hardware::graphics::composer3::Composition::INVALID: return "Invalid"; - case hardware::graphics::composer::hal::Composition::CLIENT: + case aidl::android::hardware::graphics::composer3::Composition::CLIENT: return "Client"; - case hardware::graphics::composer::hal::Composition::DEVICE: + case aidl::android::hardware::graphics::composer3::Composition::DEVICE: return "Device"; - case hardware::graphics::composer::hal::Composition::SOLID_COLOR: + case aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR: return "SolidColor"; - case hardware::graphics::composer::hal::Composition::CURSOR: + case aidl::android::hardware::graphics::composer3::Composition::CURSOR: return "Cursor"; - case hardware::graphics::composer::hal::Composition::SIDEBAND: + case aidl::android::hardware::graphics::composer3::Composition::SIDEBAND: return "Sideband"; default: return "Unknown"; diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index 11d41c063e..18f24c1dcd 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -278,7 +278,7 @@ Error HidlComposer::getActiveConfig(Display display, Config* outConfig) { Error HidlComposer::getChangedCompositionTypes( Display display, std::vector* outLayers, - std::vector* outTypes) { + std::vector* outTypes) { mReader.takeChangedCompositionTypes(display, outLayers, outTypes); return Error::NONE; } @@ -618,11 +618,17 @@ Error HidlComposer::setLayerColor(Display display, Layer layer, return Error::NONE; } -Error HidlComposer::setLayerCompositionType(Display display, Layer layer, - IComposerClient::Composition type) { +static IComposerClient::Composition to_hidl_type( + aidl::android::hardware::graphics::composer3::Composition type) { + return static_cast(type); +} + +Error HidlComposer::setLayerCompositionType( + Display display, Layer layer, + aidl::android::hardware::graphics::composer3::Composition type) { mWriter.selectDisplay(display); mWriter.selectLayer(layer); - mWriter.setLayerCompositionType(type); + mWriter.setLayerCompositionType(to_hidl_type(type)); return Error::NONE; } @@ -1266,7 +1272,8 @@ bool CommandReader::parseSetChangedCompositionTypes(uint16_t length) { mCurrentReturnData->compositionTypes.reserve(count); while (count > 0) { auto layer = read64(); - auto type = static_cast(readSigned()); + auto type = static_cast( + readSigned()); mCurrentReturnData->changedLayers.push_back(layer); mCurrentReturnData->compositionTypes.push_back(type); @@ -1394,7 +1401,7 @@ bool CommandReader::hasChanges(Display display, uint32_t* outNumChangedCompositi void CommandReader::takeChangedCompositionTypes( Display display, std::vector* outLayers, - std::vector* outTypes) { + std::vector* outTypes) { auto found = mReturnData.find(display); if (found == mReturnData.end()) { outLayers->clear(); diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index 18c0635dd2..5b2219e45b 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -37,6 +37,8 @@ #include #include +#include + // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" @@ -92,8 +94,9 @@ public: uint32_t* outNumLayerRequestMasks) const; // Get and clear saved changed composition types. - void takeChangedCompositionTypes(Display display, std::vector* outLayers, - std::vector* outTypes); + void takeChangedCompositionTypes( + Display display, std::vector* outLayers, + std::vector* outTypes); // Get and clear saved display requests. void takeDisplayRequests(Display display, uint32_t* outDisplayRequestMask, @@ -130,7 +133,7 @@ private: uint32_t displayRequests = 0; std::vector changedLayers; - std::vector compositionTypes; + std::vector compositionTypes; std::vector requestedLayers; std::vector requestMasks; @@ -188,8 +191,10 @@ public: Error destroyLayer(Display display, Layer layer) override; Error getActiveConfig(Display display, Config* outConfig) override; - Error getChangedCompositionTypes(Display display, std::vector* outLayers, - std::vector* outTypes) override; + Error getChangedCompositionTypes( + Display display, std::vector* outLayers, + std::vector* outTypes) + override; Error getColorModes(Display display, std::vector* outModes) override; Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) override; @@ -242,8 +247,9 @@ public: const std::vector& damage) override; Error setLayerBlendMode(Display display, Layer layer, IComposerClient::BlendMode mode) override; Error setLayerColor(Display display, Layer layer, const IComposerClient::Color& color) override; - Error setLayerCompositionType(Display display, Layer layer, - IComposerClient::Composition type) override; + Error setLayerCompositionType( + Display display, Layer layer, + aidl::android::hardware::graphics::composer3::Composition type) override; Error setLayerDataspace(Display display, Layer layer, Dataspace dataspace) override; Error setLayerDisplayFrame(Display display, Layer layer, const IComposerClient::Rect& frame) override; diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp index 845176c112..cc85352dc7 100644 --- a/services/surfaceflinger/EffectLayer.cpp +++ b/services/surfaceflinger/EffectLayer.cpp @@ -109,7 +109,8 @@ void EffectLayer::preparePerFrameCompositionState() { auto* compositionState = editCompositionState(); compositionState->color = getColor(); - compositionState->compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; + compositionState->compositionType = + aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR; } sp EffectLayer::getCompositionEngineLayerFE() const { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b39515955c..6e9138c119 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -650,15 +650,16 @@ std::vector Layer::prepareClientCompo return {*layerSettings}; } -Hwc2::IComposerClient::Composition Layer::getCompositionType(const DisplayDevice& display) const { +aidl::android::hardware::graphics::composer3::Composition Layer::getCompositionType( + const DisplayDevice& display) const { const auto outputLayer = findOutputLayerForDisplay(&display); if (outputLayer == nullptr) { - return Hwc2::IComposerClient::Composition::INVALID; + return aidl::android::hardware::graphics::composer3::Composition::INVALID; } if (outputLayer->getState().hwc) { return (*outputLayer->getState().hwc).hwcCompositionType; } else { - return Hwc2::IComposerClient::Composition::CLIENT; + return aidl::android::hardware::graphics::composer3::Composition::CLIENT; } } @@ -2004,7 +2005,7 @@ LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags, if (traceFlags & LayerTracing::TRACE_COMPOSITION) { // Only populate for the primary display. if (display) { - const Hwc2::IComposerClient::Composition compositionType = getCompositionType(*display); + const auto compositionType = getCompositionType(*display); layerProto->set_hwc_composition_type(static_cast(compositionType)); } } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 3f4d48be63..31cdf0b3e4 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -1037,7 +1037,8 @@ private: // Returns true if the layer can draw shadows on its border. virtual bool canDrawShadows() const { return true; } - Hwc2::IComposerClient::Composition getCompositionType(const DisplayDevice&) const; + aidl::android::hardware::graphics::composer3::Composition getCompositionType( + const DisplayDevice&) const; /** * Returns an unsorted vector of all layers that are part of this tree. diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index f1e6e48049..554e454183 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -1029,9 +1029,10 @@ struct NoCompositionTypeVariant { } }; -template +template struct KeepCompositionTypeVariant { - static constexpr hal::Composition TYPE = CompositionType; + static constexpr aidl::android::hardware::graphics::composer3::Composition TYPE = + CompositionType; static void setupHwcSetCallExpectations(CompositionTest* test) { if (!test->mDisplayOff) { @@ -1046,10 +1047,11 @@ struct KeepCompositionTypeVariant { } }; -template +template struct ChangeCompositionTypeVariant { - static constexpr hal::Composition TYPE = FinalCompositionType; + static constexpr aidl::android::hardware::graphics::composer3::Composition TYPE = + FinalCompositionType; static void setupHwcSetCallExpectations(CompositionTest* test) { if (!test->mDisplayOff) { @@ -1063,8 +1065,9 @@ struct ChangeCompositionTypeVariant { EXPECT_CALL(*test->mComposer, getChangedCompositionTypes(HWC_DISPLAY, _, _)) .WillOnce(DoAll(SetArgPointee<1>(std::vector{ static_cast(HWC_LAYER)}), - SetArgPointee<2>(std::vector{ - FinalCompositionType}), + SetArgPointee<2>( + std::vector{FinalCompositionType}), Return(Error::NONE))); } }; @@ -1258,25 +1261,28 @@ TEST_F(CompositionTest, noLayersDoesMinimalWorkToCaptureScreen) { */ TEST_F(CompositionTest, HWCComposedNormalBufferLayerWithDirtyGeometry) { - displayRefreshCompositionDirtyGeometry< - CompositionCase, - KeepCompositionTypeVariant, - HwcCompositionResultVariant>>(); + displayRefreshCompositionDirtyGeometry, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::DEVICE>, + HwcCompositionResultVariant>>(); } TEST_F(CompositionTest, HWCComposedNormalBufferLayerWithDirtyFrame) { - displayRefreshCompositionDirtyFrame< - CompositionCase, - KeepCompositionTypeVariant, - HwcCompositionResultVariant>>(); + displayRefreshCompositionDirtyFrame, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::DEVICE>, + HwcCompositionResultVariant>>(); } TEST_F(CompositionTest, REComposedNormalBufferLayer) { - displayRefreshCompositionDirtyFrame< - CompositionCase, - ChangeCompositionTypeVariant, - RECompositionResultVariant>>(); + displayRefreshCompositionDirtyFrame, + ChangeCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::DEVICE, + aidl::android::hardware::graphics::composer3::Composition::CLIENT>, + RECompositionResultVariant>>(); } TEST_F(CompositionTest, captureScreenNormalBufferLayer) { @@ -1290,25 +1296,28 @@ TEST_F(CompositionTest, captureScreenNormalBufferLayer) { */ TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyGeometry) { - displayRefreshCompositionDirtyGeometry< - CompositionCase, - KeepCompositionTypeVariant, - HwcCompositionResultVariant>>(); + displayRefreshCompositionDirtyGeometry, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR>, + HwcCompositionResultVariant>>(); } TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyFrame) { - displayRefreshCompositionDirtyFrame< - CompositionCase, - KeepCompositionTypeVariant, - HwcCompositionResultVariant>>(); + displayRefreshCompositionDirtyFrame, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR>, + HwcCompositionResultVariant>>(); } TEST_F(CompositionTest, REComposedEffectLayer) { - displayRefreshCompositionDirtyFrame< - CompositionCase, - ChangeCompositionTypeVariant, - RECompositionResultVariant>>(); + displayRefreshCompositionDirtyFrame, + ChangeCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR, + aidl::android::hardware::graphics::composer3::Composition::CLIENT>, + RECompositionResultVariant>>(); } TEST_F(CompositionTest, captureScreenEffectLayer) { @@ -1322,25 +1331,28 @@ TEST_F(CompositionTest, captureScreenEffectLayer) { */ TEST_F(CompositionTest, HWCComposedSidebandBufferLayerWithDirtyGeometry) { - displayRefreshCompositionDirtyGeometry< - CompositionCase, - KeepCompositionTypeVariant, - HwcCompositionResultVariant>>(); + displayRefreshCompositionDirtyGeometry, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::SIDEBAND>, + HwcCompositionResultVariant>>(); } TEST_F(CompositionTest, HWCComposedSidebandBufferLayerWithDirtyFrame) { - displayRefreshCompositionDirtyFrame< - CompositionCase, - KeepCompositionTypeVariant, - HwcCompositionResultVariant>>(); + displayRefreshCompositionDirtyFrame, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::SIDEBAND>, + HwcCompositionResultVariant>>(); } TEST_F(CompositionTest, REComposedSidebandBufferLayer) { - displayRefreshCompositionDirtyFrame< - CompositionCase, - ChangeCompositionTypeVariant, - RECompositionResultVariant>>(); + displayRefreshCompositionDirtyFrame, + ChangeCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::SIDEBAND, + aidl::android::hardware::graphics::composer3::Composition::CLIENT>, + RECompositionResultVariant>>(); } TEST_F(CompositionTest, captureScreenSidebandBufferLayer) { @@ -1354,25 +1366,28 @@ TEST_F(CompositionTest, captureScreenSidebandBufferLayer) { */ TEST_F(CompositionTest, HWCComposedSecureBufferLayerWithDirtyGeometry) { - displayRefreshCompositionDirtyGeometry< - CompositionCase, - KeepCompositionTypeVariant, - HwcCompositionResultVariant>>(); + displayRefreshCompositionDirtyGeometry, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::DEVICE>, + HwcCompositionResultVariant>>(); } TEST_F(CompositionTest, HWCComposedSecureBufferLayerWithDirtyFrame) { - displayRefreshCompositionDirtyFrame< - CompositionCase, - KeepCompositionTypeVariant, - HwcCompositionResultVariant>>(); + displayRefreshCompositionDirtyFrame, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::DEVICE>, + HwcCompositionResultVariant>>(); } TEST_F(CompositionTest, REComposedSecureBufferLayer) { - displayRefreshCompositionDirtyFrame< - CompositionCase, - ChangeCompositionTypeVariant, - RECompositionResultVariant>>(); + displayRefreshCompositionDirtyFrame, + ChangeCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::DEVICE, + aidl::android::hardware::graphics::composer3::Composition::CLIENT>, + RECompositionResultVariant>>(); } TEST_F(CompositionTest, captureScreenSecureBufferLayerOnSecureDisplay) { @@ -1386,17 +1401,19 @@ TEST_F(CompositionTest, captureScreenSecureBufferLayerOnSecureDisplay) { */ TEST_F(CompositionTest, HWCComposedSecureBufferLayerOnInsecureDisplayWithDirtyGeometry) { - displayRefreshCompositionDirtyGeometry< - CompositionCase, - KeepCompositionTypeVariant, - ForcedClientCompositionResultVariant>>(); + displayRefreshCompositionDirtyGeometry, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::CLIENT>, + ForcedClientCompositionResultVariant>>(); } TEST_F(CompositionTest, HWCComposedSecureBufferLayerOnInsecureDisplayWithDirtyFrame) { - displayRefreshCompositionDirtyFrame< - CompositionCase, - KeepCompositionTypeVariant, - ForcedClientCompositionResultVariant>>(); + displayRefreshCompositionDirtyFrame, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::CLIENT>, + ForcedClientCompositionResultVariant>>(); } TEST_F(CompositionTest, captureScreenSecureBufferLayerOnInsecureDisplay) { @@ -1411,22 +1428,24 @@ TEST_F(CompositionTest, captureScreenSecureBufferLayerOnInsecureDisplay) { TEST_F(CompositionTest, HWCComposedBufferLayerWithSecureParentLayerOnInsecureDisplayWithDirtyGeometry) { - displayRefreshCompositionDirtyGeometry< - CompositionCase, - ContainerLayerVariant>, - KeepCompositionTypeVariant, - ForcedClientCompositionResultVariant>>(); + displayRefreshCompositionDirtyGeometry, + ContainerLayerVariant>, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::CLIENT>, + ForcedClientCompositionResultVariant>>(); } TEST_F(CompositionTest, HWCComposedBufferLayerWithSecureParentLayerOnInsecureDisplayWithDirtyFrame) { - displayRefreshCompositionDirtyFrame< - CompositionCase, - ContainerLayerVariant>, - KeepCompositionTypeVariant, - ForcedClientCompositionResultVariant>>(); + displayRefreshCompositionDirtyFrame, + ContainerLayerVariant>, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::CLIENT>, + ForcedClientCompositionResultVariant>>(); } TEST_F(CompositionTest, captureScreenBufferLayerWithSecureParentLayerOnInsecureDisplay) { @@ -1442,25 +1461,28 @@ TEST_F(CompositionTest, captureScreenBufferLayerWithSecureParentLayerOnInsecureD */ TEST_F(CompositionTest, HWCComposedCursorLayerWithDirtyGeometry) { - displayRefreshCompositionDirtyGeometry< - CompositionCase, - KeepCompositionTypeVariant, - HwcCompositionResultVariant>>(); + displayRefreshCompositionDirtyGeometry, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::CURSOR>, + HwcCompositionResultVariant>>(); } TEST_F(CompositionTest, HWCComposedCursorLayerWithDirtyFrame) { - displayRefreshCompositionDirtyFrame< - CompositionCase, - KeepCompositionTypeVariant, - HwcCompositionResultVariant>>(); + displayRefreshCompositionDirtyFrame, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::CURSOR>, + HwcCompositionResultVariant>>(); } TEST_F(CompositionTest, REComposedCursorLayer) { - displayRefreshCompositionDirtyFrame< - CompositionCase, - ChangeCompositionTypeVariant, - RECompositionResultVariant>>(); + displayRefreshCompositionDirtyFrame, + ChangeCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::CURSOR, + aidl::android::hardware::graphics::composer3::Composition::CLIENT>, + RECompositionResultVariant>>(); } TEST_F(CompositionTest, captureScreenCursorLayer) { @@ -1477,7 +1499,8 @@ TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyGeometry) mDisplayOff = true; displayRefreshCompositionDirtyGeometry, - KeepCompositionTypeVariant, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::DEVICE>, HwcCompositionResultVariant>>(); } @@ -1485,7 +1508,8 @@ TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyFrame) { mDisplayOff = true; displayRefreshCompositionDirtyFrame, - KeepCompositionTypeVariant, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::DEVICE>, HwcCompositionResultVariant>>(); } @@ -1493,8 +1517,9 @@ TEST_F(CompositionTest, displayOffREComposedNormalBufferLayer) { mDisplayOff = true; displayRefreshCompositionDirtyFrame, - ChangeCompositionTypeVariant, + ChangeCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::DEVICE, + aidl::android::hardware::graphics::composer3::Composition::CLIENT>, RECompositionResultVariant>>(); } @@ -1509,17 +1534,19 @@ TEST_F(CompositionTest, captureScreenNormalBufferLayerOnPoweredOffDisplay) { */ TEST_F(CompositionTest, DebugOptionForcingClientCompositionOfBufferLayerWithDirtyGeometry) { - displayRefreshCompositionDirtyGeometry< - CompositionCase, - KeepCompositionTypeVariant, - ForcedClientCompositionViaDebugOptionResultVariant>>(); + displayRefreshCompositionDirtyGeometry, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::CLIENT>, + ForcedClientCompositionViaDebugOptionResultVariant>>(); } TEST_F(CompositionTest, DebugOptionForcingClientCompositionOfBufferLayerWithDirtyFrame) { - displayRefreshCompositionDirtyFrame< - CompositionCase, - KeepCompositionTypeVariant, - ForcedClientCompositionViaDebugOptionResultVariant>>(); + displayRefreshCompositionDirtyFrame, + KeepCompositionTypeVariant< + aidl::android::hardware::graphics::composer3::Composition::CLIENT>, + ForcedClientCompositionViaDebugOptionResultVariant>>(); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 100a78d854..0067997398 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -270,7 +270,8 @@ public: layer->editCompositionState()->sidebandStream = sidebandStream; } - void setLayerCompositionType(const sp& layer, hal::Composition type) { + void setLayerCompositionType(const sp& layer, + aidl::android::hardware::graphics::composer3::Composition type) { auto outputLayer = findOutputLayerForDisplay(layer, mFlinger->getDefaultDisplayDevice()); LOG_ALWAYS_FATAL_IF(!outputLayer); auto& state = outputLayer->editState(); diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index 1debd65ac4..c3250d52d3 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -61,7 +61,8 @@ public: MOCK_METHOD2(destroyLayer, Error(Display, Layer)); MOCK_METHOD2(getActiveConfig, Error(Display, Config*)); MOCK_METHOD3(getChangedCompositionTypes, - Error(Display, std::vector*, std::vector*)); + Error(Display, std::vector*, + std::vector*)); MOCK_METHOD2(getColorModes, Error(Display, std::vector*)); MOCK_METHOD4(getDisplayAttribute, Error(Display, Config config, IComposerClient::Attribute, int32_t*)); @@ -95,7 +96,8 @@ public: Error(Display, Layer, const std::vector&)); MOCK_METHOD3(setLayerBlendMode, Error(Display, Layer, IComposerClient::BlendMode)); MOCK_METHOD3(setLayerColor, Error(Display, Layer, const IComposerClient::Color&)); - MOCK_METHOD3(setLayerCompositionType, Error(Display, Layer, IComposerClient::Composition)); + MOCK_METHOD3(setLayerCompositionType, + Error(Display, Layer, aidl::android::hardware::graphics::composer3::Composition)); MOCK_METHOD3(setLayerDataspace, Error(Display, Layer, Dataspace)); MOCK_METHOD3(setLayerPerFrameMetadata, Error(Display, Layer, const std::vector&)); diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h index 83a0996fe6..d4fefee167 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -38,7 +38,9 @@ public: MOCK_METHOD((base::expected, hal::Error>), createLayer, (), (override)); MOCK_METHOD(hal::Error, getChangedCompositionTypes, - ((std::unordered_map *)), (override)); + ((std::unordered_map *)), + (override)); MOCK_METHOD(hal::Error, getColorModes, (std::vector *), (const, override)); MOCK_METHOD(int32_t, getSupportedPerFrameMetadata, (), (const, override)); MOCK_METHOD(hal::Error, getRenderIntents, (hal::ColorMode, std::vector *), @@ -103,7 +105,8 @@ public: MOCK_METHOD(hal::Error, setSurfaceDamage, (const android::Region &), (override)); MOCK_METHOD(hal::Error, setBlendMode, (hal::BlendMode), (override)); MOCK_METHOD(hal::Error, setColor, (hal::Color), (override)); - MOCK_METHOD(hal::Error, setCompositionType, (hal::Composition), (override)); + MOCK_METHOD(hal::Error, setCompositionType, + (aidl::android::hardware::graphics::composer3::Composition), (override)); MOCK_METHOD(hal::Error, setDataspace, (android::ui::Dataspace), (override)); MOCK_METHOD(hal::Error, setPerFrameMetadata, (const int32_t, const android::HdrMetadata &), (override)); -- cgit v1.2.3-59-g8ed1b From d37343ba07ce5d46cf4fd7d5facfbe2c06568149 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 12 Jan 2022 16:18:56 -0800 Subject: SF: Add new fields to transactions proto - track layer handle removal so layer lifecycle can be recreated accurately when rebuilding layer state - track buffer format since it affects opacity - track transaction ids to track transactions across the system - also fixes relative z tracking Test: atest TransactionProtoParserTest Bug: 200284593 Change-Id: I037e40219f9fee8957051352beeba88681b8cf43 --- services/surfaceflinger/Android.bp | 1 - services/surfaceflinger/BufferLayer.cpp | 4 +++ services/surfaceflinger/BufferLayer.h | 1 + services/surfaceflinger/Layer.cpp | 4 +-- services/surfaceflinger/Layer.h | 3 ++ services/surfaceflinger/LayerProtoHelper.cpp | 14 ++++----- services/surfaceflinger/LayerProtoHelper.h | 3 +- .../Tracing/TransactionProtoParser.cpp | 35 +++++++++++++++++----- .../Tracing/TransactionProtoParser.h | 2 ++ .../surfaceflinger/Tracing/TransactionTracing.cpp | 16 +++++++++- .../surfaceflinger/Tracing/TransactionTracing.h | 1 + services/surfaceflinger/layerproto/layers.proto | 1 + .../surfaceflinger/layerproto/transactions.proto | 33 ++++++++++++++++++-- 13 files changed, 97 insertions(+), 21 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 26ac269ad7..61ff53cfdf 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -227,7 +227,6 @@ cc_defaults { "libcutils", "libdisplayservicehidl", "libhidlbase", - "liblayers_proto", "liblog", "libprocessgroup", "libsync", diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 649138a48e..e797b5d4bb 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -820,6 +820,10 @@ bool BufferLayer::bufferNeedsFiltering() const { return isFixedSize(); } +const std::shared_ptr& BufferLayer::getExternalTexture() const { + return mBufferInfo.mBuffer; +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 34d11ac579..99267be673 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -111,6 +111,7 @@ public: ui::Dataspace getDataSpace() const override; sp getBuffer() const override; + const std::shared_ptr& getExternalTexture() const override; ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5948a78559..9dc185be35 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2022,9 +2022,9 @@ LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags, void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, const DisplayDevice* display) { const ui::Transform transform = getTransform(); - auto buffer = getBuffer(); + auto buffer = getExternalTexture(); if (buffer != nullptr) { - LayerProtoHelper::writeToProto(buffer, + LayerProtoHelper::writeToProto(*buffer, [&]() { return layerInfo->mutable_active_buffer(); }); LayerProtoHelper::writeToProtoDeprecated(ui::Transform(getBufferTransform()), layerInfo->mutable_buffer_transform()); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 0d2618acf5..4cdd8fa24b 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -565,6 +565,9 @@ public: virtual uint32_t getBufferTransform() const { return 0; } virtual sp getBuffer() const { return nullptr; } + virtual const std::shared_ptr& getExternalTexture() const { + return mDrawingState.buffer; + }; virtual ui::Transform::RotationFlags getTransformHint() const { return ui::Transform::ROT_0; } diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index ee23561136..015caa6a9b 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -154,16 +154,16 @@ void LayerProtoHelper::writeTransformToProto(const ui::Transform& transform, } } -void LayerProtoHelper::writeToProto(const sp& buffer, +void LayerProtoHelper::writeToProto(const renderengine::ExternalTexture& buffer, std::function getActiveBufferProto) { - if (buffer->getWidth() != 0 || buffer->getHeight() != 0 || buffer->getStride() != 0 || - buffer->format != 0) { + if (buffer.getBuffer()->getWidth() != 0 || buffer.getBuffer()->getHeight() != 0 || + buffer.getBuffer()->getUsage() != 0 || buffer.getBuffer()->getPixelFormat() != 0) { // Use a lambda do avoid writing the object header when the object is empty ActiveBufferProto* activeBufferProto = getActiveBufferProto(); - activeBufferProto->set_width(buffer->getWidth()); - activeBufferProto->set_height(buffer->getHeight()); - activeBufferProto->set_stride(buffer->getStride()); - activeBufferProto->set_format(buffer->format); + activeBufferProto->set_width(buffer.getBuffer()->getWidth()); + activeBufferProto->set_height(buffer.getBuffer()->getHeight()); + activeBufferProto->set_format(buffer.getBuffer()->getPixelFormat()); + activeBufferProto->set_usage(buffer.getBuffer()->getUsage()); } } diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h index 249ec4281f..6ade1435e5 100644 --- a/services/surfaceflinger/LayerProtoHelper.h +++ b/services/surfaceflinger/LayerProtoHelper.h @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -48,7 +49,7 @@ public: TransformProto* transformProto); static void writeTransformToProto(const ui::Transform& transform, TransformProto* transformProto); - static void writeToProto(const sp& buffer, + static void writeToProto(const renderengine::ExternalTexture& buffer, std::function getActiveBufferProto); static void writeToProto(const gui::WindowInfo& inputInfo, const wp& touchableRegionBounds, diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index 849de22a41..056015dc3f 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -31,6 +31,7 @@ proto::TransactionState TransactionProtoParser::toProto(const TransactionState& proto.set_vsync_id(t.frameTimelineInfo.vsyncId); proto.set_input_event_id(t.frameTimelineInfo.inputEventId); proto.set_post_time(t.postTime); + proto.set_transaction_id(t.id); for (auto& layerState : t.states) { proto.mutable_layer_changes()->Add(std::move(toProto(layerState.state, getLayerId))); @@ -52,6 +53,9 @@ proto::TransactionState TransactionProtoParser::toProto( bufferProto->set_buffer_id(state.bufferId); bufferProto->set_width(state.bufferWidth); bufferProto->set_height(state.bufferHeight); + bufferProto->set_pixel_format( + static_cast(state.pixelFormat)); + bufferProto->set_usage(state.bufferUsage); } layerProto.set_has_sideband_stream(state.hasSidebandStream); layerProto.set_layer_id(state.layerId); @@ -136,6 +140,9 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer, bufferProto->set_buffer_id(layer.bufferData->getId()); bufferProto->set_width(layer.bufferData->getWidth()); bufferProto->set_height(layer.bufferData->getHeight()); + bufferProto->set_pixel_format(static_cast( + layer.bufferData->getPixelFormat())); + bufferProto->set_usage(layer.bufferData->getUsage()); } bufferProto->set_frame_number(layer.bufferData->frameNumber); bufferProto->set_flags(layer.bufferData->flags.get()); @@ -169,6 +176,7 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer, ? getLayerId(layer.relativeLayerSurfaceControl->getHandle()) : -1; proto.set_relative_parent_id(layerId); + proto.set_z(layer.z); } if (layer.what & layer_state_t::eInputInfoChanged) { @@ -291,6 +299,8 @@ TransactionState TransactionProtoParser::fromProto(const proto::TransactionState t.frameTimelineInfo.vsyncId = proto.vsync_id(); t.frameTimelineInfo.inputEventId = proto.input_event_id(); t.postTime = proto.post_time(); + t.id = proto.transaction_id(); + int32_t layerCount = proto.layer_changes_size(); t.states.reserve(static_cast(layerCount)); for (int i = 0; i < layerCount; i++) { @@ -335,6 +345,8 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, outState.bufferId = bufferProto.buffer_id(); outState.bufferWidth = bufferProto.width(); outState.bufferHeight = bufferProto.height(); + outState.pixelFormat = bufferProto.pixel_format(); + outState.bufferUsage = bufferProto.usage(); } if (proto.what() & layer_state_t::eSidebandStreamChanged) { outState.hasSidebandStream = proto.has_sideband_stream(); @@ -432,15 +444,24 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, if ((proto.what() & layer_state_t::eReparent) && (getLayerHandle != nullptr)) { int32_t layerId = proto.parent_id(); - layer.parentSurfaceControlForChild = - new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId), - nullptr, layerId); + if (layerId == -1) { + layer.parentSurfaceControlForChild = nullptr; + } else { + layer.parentSurfaceControlForChild = + new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId), + nullptr, layerId); + } } - if ((proto.what() & layer_state_t::eRelativeLayerChanged) && (getLayerHandle != nullptr)) { + if (proto.what() & layer_state_t::eRelativeLayerChanged) { int32_t layerId = proto.relative_parent_id(); - layer.relativeLayerSurfaceControl = - new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId), - nullptr, layerId); + if (layerId == -1) { + layer.relativeLayerSurfaceControl = nullptr; + } else if (getLayerHandle != nullptr) { + layer.relativeLayerSurfaceControl = + new SurfaceControl(SurfaceComposerClient::getDefault(), getLayerHandle(layerId), + nullptr, layerId); + } + layer.z = proto.z(); } if ((proto.what() & layer_state_t::eInputInfoChanged) && proto.has_window_info_handle()) { diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h index b78d3d96da..bb0b13478e 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.h +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h @@ -34,6 +34,8 @@ struct TracingLayerState : layer_state_t { uint64_t bufferId; uint32_t bufferHeight; uint32_t bufferWidth; + int32_t pixelFormat; + uint64_t bufferUsage; bool hasSidebandStream; int32_t parentId; int32_t relativeParentId; diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp index b5966d5837..c126911152 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.cpp +++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp @@ -210,6 +210,13 @@ void TransactionTracing::addEntry(const std::vector& comm removedEntries.reserve(removedEntries.size() + entries.size()); removedEntries.insert(removedEntries.end(), std::make_move_iterator(entries.begin()), std::make_move_iterator(entries.end())); + + entryProto.mutable_removed_layer_handles()->Reserve( + static_cast(mRemovedLayerHandles.size())); + for (auto& handle : mRemovedLayerHandles) { + entryProto.mutable_removed_layer_handles()->Add(handle); + } + mRemovedLayerHandles.clear(); } proto::TransactionTraceEntry removedEntryProto; @@ -267,7 +274,14 @@ void TransactionTracing::onLayerRemoved(int32_t layerId) { void TransactionTracing::onHandleRemoved(BBinder* layerHandle) { std::scoped_lock lock(mTraceLock); - mLayerHandles.erase(layerHandle); + auto it = mLayerHandles.find(layerHandle); + if (it == mLayerHandles.end()) { + ALOGW("handle not found. %p", layerHandle); + return; + } + + mRemovedLayerHandles.push_back(it->second); + mLayerHandles.erase(it); } void TransactionTracing::tryPushToTracingThread() { diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h index 26a37586dc..bb6f3fd678 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.h +++ b/services/surfaceflinger/Tracing/TransactionTracing.h @@ -88,6 +88,7 @@ private: std::vector mCreatedLayers GUARDED_BY(mTraceLock); std::unordered_map mLayerHandles GUARDED_BY(mTraceLock); + std::vector mRemovedLayerHandles GUARDED_BY(mTraceLock); std::map mStartingStates GUARDED_BY(mTraceLock); // We do not want main thread to block so main thread will try to acquire mMainThreadLock, diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto index 4529905566..2e9e659880 100644 --- a/services/surfaceflinger/layerproto/layers.proto +++ b/services/surfaceflinger/layerproto/layers.proto @@ -155,6 +155,7 @@ message ActiveBufferProto { uint32 height = 2; uint32 stride = 3; int32 format = 4; + uint64 usage = 5; } message BarrierLayerProto { diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto index 3cb1076fb3..9b076bd282 100644 --- a/services/surfaceflinger/layerproto/transactions.proto +++ b/services/surfaceflinger/layerproto/transactions.proto @@ -46,6 +46,7 @@ message TransactionTraceEntry { repeated int32 removed_layers = 5; repeated DisplayState added_displays = 6; repeated int32 removed_displays = 7; + repeated int32 removed_layer_handles = 8; } message LayerCreationArgs { @@ -62,8 +63,9 @@ message TransactionState { int64 vsync_id = 3; int32 input_event_id = 4; int64 post_time = 5; - repeated LayerState layer_changes = 6; - repeated DisplayState display_changes = 7; + uint64 transaction_id = 6; + repeated LayerState layer_changes = 7; + repeated DisplayState display_changes = 8; } // Keep insync with layer_state_t @@ -78,28 +80,35 @@ message LayerState { eLayerChanged = 0x00000002; eSizeChanged = 0x00000004; eAlphaChanged = 0x00000008; + eMatrixChanged = 0x00000010; eTransparentRegionChanged = 0x00000020; eFlagsChanged = 0x00000040; eLayerStackChanged = 0x00000080; + eReleaseBufferListenerChanged = 0x00000400; eShadowRadiusChanged = 0x00000800; + eLayerCreated = 0x00001000; eBufferCropChanged = 0x00002000; eRelativeLayerChanged = 0x00004000; eReparent = 0x00008000; + eColorChanged = 0x00010000; eDestroySurface = 0x00020000; eTransformChanged = 0x00040000; eTransformToDisplayInverseChanged = 0x00080000; + eCropChanged = 0x00100000; eBufferChanged = 0x00200000; eAcquireFenceChanged = 0x00400000; eDataspaceChanged = 0x00800000; + eHdrMetadataChanged = 0x01000000; eSurfaceDamageRegionChanged = 0x02000000; eApiChanged = 0x04000000; eSidebandStreamChanged = 0x08000000; + eColorTransformChanged = 0x10000000; eHasListenerCallbacksChanged = 0x20000000; eInputInfoChanged = 0x40000000; @@ -182,6 +191,26 @@ message LayerState { } uint32 flags = 5; uint64 cached_buffer_id = 6; + + enum PixelFormat { + PIXEL_FORMAT_UNKNOWN = 0; + PIXEL_FORMAT_CUSTOM = -4; + PIXEL_FORMAT_TRANSLUCENT = -3; + PIXEL_FORMAT_TRANSPARENT = -2; + PIXEL_FORMAT_OPAQUE = -1; + PIXEL_FORMAT_RGBA_8888 = 1; + PIXEL_FORMAT_RGBX_8888 = 2; + PIXEL_FORMAT_RGB_888 = 3; + PIXEL_FORMAT_RGB_565 = 4; + PIXEL_FORMAT_BGRA_8888 = 5; + PIXEL_FORMAT_RGBA_5551 = 6; + PIXEL_FORMAT_RGBA_4444 = 7; + PIXEL_FORMAT_RGBA_FP16 = 22; + PIXEL_FORMAT_RGBA_1010102 = 43; + PIXEL_FORMAT_R_8 = 0x38; + } + PixelFormat pixel_format = 7; + uint64 usage = 8; } BufferData buffer_data = 22; int32 api = 23; -- cgit v1.2.3-59-g8ed1b From a84a2200c8935ce130f649e277d3a849c24c618f Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 12 Jan 2022 20:12:55 -0800 Subject: SF: Update static sequence counter when injecting a sequence number When generating layer trace, layers will be created with a sequence number. However any supporting layer that is created (when mirroring or color layer for blast) will use the static counter to gets its sequence number. This might result in layers with duplicate sequence numbers. Fix this by updating the static sequence counter if a sequence number is injected. Test: atest TransactionTracingTest Bug: 200284593 Change-Id: Ib64227a088d1cbf76b977604eaeb3b1421af63f5 --- services/surfaceflinger/Layer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 9dc185be35..fa2c92dd32 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -101,7 +101,9 @@ Layer::Layer(const LayerCreationArgs& args) if (args.flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure; if (args.flags & ISurfaceComposerClient::eSkipScreenshot) layerFlags |= layer_state_t::eLayerSkipScreenshot; - + if (args.sequence) { + sSequence = *args.sequence + 1; + } mDrawingState.flags = layerFlags; mDrawingState.active_legacy.transform.set(0, 0); mDrawingState.crop.makeInvalid(); -- cgit v1.2.3-59-g8ed1b From de6d7b467e572d384f2bc1bc788259340ebe2f93 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Fri, 7 Jan 2022 18:23:06 -0800 Subject: SurfaceFlinger: Add Transaction#sanitize Various elements of the Transaction interface require a permission in order to apply. In particular the setTrustedOverlay and setInputWindowInfo fields. These permission checks are implemented by checking the PID and the UID of the process which sent the transaction. Unfortunately widespread use of transaction merging makes this inadequate. At the moment IWindowSession#finishDrawing seems to be the only boundary on which transactions move from client to system processes, and so we expose a sanitize method and use it from there to resolve the situation in an easily backportable way. Moving forward it likely make sense to move security sensitive interfaces off of Transaction. Most of the things behind permissions currently are not truly security sensitive, more of just a request not to use them. It was also considered to sanitize transactions at all process boundaries through writeToParcel, however this could be disruptive as previously permissioned processes (WM and SysUI) could freely exchange transactions. As the change needs to be backportable the lowest risk option was chosen. Bug: 213644870 Test: Existing tests pass Change-Id: I424f45bc30ea8e56e4c4493203ee0749eabf239c --- libs/gui/LayerState.cpp | 73 ++++++++++++++++++ libs/gui/SurfaceComposerClient.cpp | 8 +- libs/gui/include/gui/LayerState.h | 7 ++ libs/gui/include/gui/SurfaceComposerClient.h | 8 ++ services/surfaceflinger/BufferStateLayer.cpp | 9 +-- services/surfaceflinger/BufferStateLayer.h | 3 +- services/surfaceflinger/Layer.cpp | 8 +- services/surfaceflinger/Layer.h | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 106 ++++++++------------------- services/surfaceflinger/SurfaceFlinger.h | 2 +- 10 files changed, 129 insertions(+), 98 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 27d86bb4e2..eec4a874b9 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -340,6 +340,79 @@ void DisplayState::merge(const DisplayState& other) { } } +void layer_state_t::sanitize(int32_t permissions) { + // TODO: b/109894387 + // + // SurfaceFlinger's renderer is not prepared to handle cropping in the face of arbitrary + // rotation. To see the problem observe that if we have a square parent, and a child + // of the same size, then we rotate the child 45 degrees around its center, the child + // must now be cropped to a non rectangular 8 sided region. + // + // Of course we can fix this in the future. For now, we are lucky, SurfaceControl is + // private API, and arbitrary rotation is used in limited use cases, for instance: + // - WindowManager only uses rotation in one case, which is on a top level layer in which + // cropping is not an issue. + // - Launcher, as a privileged app, uses this to transition an application to PiP + // (picture-in-picture) mode. + // + // However given that abuse of rotation matrices could lead to surfaces extending outside + // of cropped areas, we need to prevent non-root clients without permission + // ACCESS_SURFACE_FLINGER nor ROTATE_SURFACE_FLINGER + // (a.k.a. everyone except WindowManager / tests / Launcher) from setting non rectangle + // preserving transformations. + if (what & eMatrixChanged) { + if (!(permissions & Permission::ROTATE_SURFACE_FLINGER)) { + ui::Transform t; + t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); + if (!t.preserveRects()) { + what &= ~eMatrixChanged; + ALOGE("Stripped non rect preserving matrix in sanitize"); + } + } + } + + if (what & eFlagsChanged) { + if ((flags & eLayerIsDisplayDecoration) && + !(permissions & Permission::INTERNAL_SYSTEM_WINDOW)) { + flags &= ~eLayerIsDisplayDecoration; + ALOGE("Stripped attempt to set LayerIsDisplayDecoration in sanitize"); + } + } + + if (what & layer_state_t::eInputInfoChanged) { + if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) { + what &= ~eInputInfoChanged; + ALOGE("Stripped attempt to set eInputInfoChanged in sanitize"); + } + } + if (what & layer_state_t::eTrustedOverlayChanged) { + if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) { + what &= ~eTrustedOverlayChanged; + ALOGE("Stripped attempt to set eTrustedOverlay in sanitize"); + } + } + if (what & layer_state_t::eDropInputModeChanged) { + if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) { + what &= ~eDropInputModeChanged; + ALOGE("Stripped attempt to set eDropInputModeChanged in sanitize"); + } + } + if (what & layer_state_t::eFrameRateSelectionPriority) { + if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) { + what &= ~eFrameRateSelectionPriority; + ALOGE("Stripped attempt to set eFrameRateSelectionPriority in sanitize"); + } + } + if (what & layer_state_t::eFrameRateChanged) { + if (!ValidateFrameRate(frameRate, frameRateCompatibility, + changeFrameRateStrategy, + "layer_state_t::sanitize", + permissions & Permission::ACCESS_SURFACE_FLINGER)) { + what &= ~eFrameRateChanged; // logged in ValidateFrameRate + } + } +} + void layer_state_t::merge(const layer_state_t& other) { if (other.what & ePositionChanged) { what |= ePositionChanged; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 31456cda7e..a7b2bcdc48 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -565,6 +565,13 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mListenerCallbacks = other.mListenerCallbacks; } +void SurfaceComposerClient::Transaction::sanitize() { + for (auto & [handle, composerState] : mComposerStates) { + composerState.state.sanitize(0 /* permissionMask */); + } + mInputWindowCommands.clear(); +} + std::unique_ptr SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) { auto transaction = std::make_unique(); @@ -646,7 +653,6 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel if (composerState.read(*parcel) == BAD_VALUE) { return BAD_VALUE; } - composerStates[surfaceControlHandle] = composerState; } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 968ace93b9..ef4ab1f91d 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -113,6 +113,12 @@ public: * Used to communicate layer information between SurfaceFlinger and its clients. */ struct layer_state_t { + enum Permission { + ACCESS_SURFACE_FLINGER = 0x1, + ROTATE_SURFACE_FLINGER = 0x2, + INTERNAL_SYSTEM_WINDOW = 0x4, + }; + enum { eLayerHidden = 0x01, // SURFACE_HIDDEN in SurfaceControl.java eLayerOpaque = 0x02, // SURFACE_OPAQUE @@ -181,6 +187,7 @@ struct layer_state_t { status_t read(const Parcel& input); bool hasBufferChanges() const; bool hasValidBuffer() const; + void sanitize(int32_t permissions); struct matrix22_t { float dsdx{0}; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 4f928781d9..366577dd31 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -624,6 +624,14 @@ public: void setAnimationTransaction(); void setEarlyWakeupStart(); void setEarlyWakeupEnd(); + + /** + * Strip the transaction of all permissioned requests, required when + * accepting transactions across process boundaries. + * + * TODO (b/213644870): Remove all permissioned things from Transaction + */ + void sanitize(); }; status_t clearLayerFrameStats(const sp& token) const; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 0c938723ba..40fc342ec8 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -316,8 +316,7 @@ bool BufferStateLayer::updateGeometry() { return assignTransform(&mDrawingState.transform, t); } -bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix, - bool allowNonRectPreservingTransforms) { +bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix) { if (mRequestedTransform.dsdx() == matrix.dsdx && mRequestedTransform.dtdy() == matrix.dtdy && mRequestedTransform.dtdx() == matrix.dtdx && mRequestedTransform.dsdy() == matrix.dsdy) { return false; @@ -326,12 +325,6 @@ bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix, ui::Transform t; t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); - if (!allowNonRectPreservingTransforms && !t.preserveRects()) { - ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER nor " - "ROTATE_SURFACE_FLINGER ignored"); - return false; - } - mRequestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); mDrawingState.sequence++; diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 2f613d7f26..248e013ef3 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -70,8 +70,7 @@ public: bool addFrameEvent(const sp& acquireFence, nsecs_t postedTime, nsecs_t requestedPresentTime) override; bool setPosition(float /*x*/, float /*y*/) override; - bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/, - bool /*allowNonRectPreservingTransforms*/); + bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/); // Override to ignore legacy layer state properties that are not used by BufferStateLayer bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index fa2c92dd32..7af12375d4 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -945,16 +945,10 @@ bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) { setTransactionFlags(eTransactionNeeded); return true; } -bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix, - bool allowNonRectPreservingTransforms) { +bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) { ui::Transform t; t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); - if (!allowNonRectPreservingTransforms && !t.preserveRects()) { - ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER nor " - "ROTATE_SURFACE_FLINGER ignored"); - return false; - } mDrawingState.sequence++; mDrawingState.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); mDrawingState.modified = true; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4cdd8fa24b..c7a3937f1e 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -366,8 +366,7 @@ public: // Set a 2x2 transformation matrix on the layer. This transform // will be applied after parent transforms, but before any final // producer specified transform. - virtual bool setMatrix(const layer_state_t::matrix22_t& matrix, - bool allowNonRectPreservingTransforms); + virtual bool setMatrix(const layer_state_t::matrix22_t& matrix); // This second set of geometry attributes are controlled by // setGeometryAppliesWithResize, and their default mode is to be diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 88317e98fe..6361f5bbf7 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -271,12 +271,6 @@ bool validateCompositionDataspace(Dataspace dataspace) { } -enum Permission { - ACCESS_SURFACE_FLINGER = 0x1, - ROTATE_SURFACE_FLINGER = 0x2, - INTERNAL_SYSTEM_WINDOW = 0x4, -}; - struct IdleTimerConfig { int32_t timeoutMs; bool supportKernelIdleTimer; @@ -3995,19 +3989,20 @@ status_t SurfaceFlinger::setTransactionState( ATRACE_CALL(); uint32_t permissions = - callingThreadHasUnscopedSurfaceFlingerAccess() ? Permission::ACCESS_SURFACE_FLINGER : 0; + callingThreadHasUnscopedSurfaceFlingerAccess() ? + layer_state_t::Permission::ACCESS_SURFACE_FLINGER : 0; // Avoid checking for rotation permissions if the caller already has ACCESS_SURFACE_FLINGER // permissions. - if ((permissions & Permission::ACCESS_SURFACE_FLINGER) || + if ((permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER) || callingThreadHasRotateSurfaceFlingerAccess()) { - permissions |= Permission::ROTATE_SURFACE_FLINGER; + permissions |= layer_state_t::Permission::ROTATE_SURFACE_FLINGER; } if (callingThreadHasInternalSystemWindowAccess()) { - permissions |= Permission::INTERNAL_SYSTEM_WINDOW; + permissions |= layer_state_t::Permission::INTERNAL_SYSTEM_WINDOW; } - if (!(permissions & Permission::ACCESS_SURFACE_FLINGER) && + if (!(permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER) && (flags & (eEarlyWakeupStart | eEarlyWakeupEnd))) { ALOGE("Only WindowManager is allowed to use eEarlyWakeup[Start|End] flags"); flags &= ~(eEarlyWakeupStart | eEarlyWakeupEnd); @@ -4069,7 +4064,8 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin uint32_t clientStateFlags = 0; for (const ComposerState& state : states) { - clientStateFlags |= setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, + ComposerState stateCopy = state; + clientStateFlags |= setClientStateLocked(frameTimelineInfo, stateCopy, desiredPresentTime, isAutoTimestamp, postTime, permissions); if ((flags & eAnimation) && state.state.surface) { if (const auto layer = fromHandle(state.state.surface).promote()) { @@ -4083,7 +4079,7 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin transactionFlags |= clientStateFlags; - if (permissions & Permission::ACCESS_SURFACE_FLINGER) { + if (permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER) { transactionFlags |= addInputWindowCommands(inputWindowCommands); } else if (!inputWindowCommands.empty()) { ALOGE("Only privileged callers are allowed to send input commands."); @@ -4194,11 +4190,11 @@ bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermis } uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTimelineInfo, - const ComposerState& composerState, + ComposerState& composerState, int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, uint32_t permissions) { - const layer_state_t& s = composerState.state; - const bool privileged = permissions & Permission::ACCESS_SURFACE_FLINGER; + layer_state_t& s = composerState.state; + s.sanitize(permissions); std::vector filteredListeners; for (auto& listener : s.listeners) { @@ -4316,43 +4312,14 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } } if (what & layer_state_t::eMatrixChanged) { - // TODO: b/109894387 - // - // SurfaceFlinger's renderer is not prepared to handle cropping in the face of arbitrary - // rotation. To see the problem observe that if we have a square parent, and a child - // of the same size, then we rotate the child 45 degrees around it's center, the child - // must now be cropped to a non rectangular 8 sided region. - // - // Of course we can fix this in the future. For now, we are lucky, SurfaceControl is - // private API, and arbitrary rotation is used in limited use cases, for instance: - // - WindowManager only uses rotation in one case, which is on a top level layer in which - // cropping is not an issue. - // - Launcher, as a privileged app, uses this to transition an application to PiP - // (picture-in-picture) mode. - // - // However given that abuse of rotation matrices could lead to surfaces extending outside - // of cropped areas, we need to prevent non-root clients without permission - // ACCESS_SURFACE_FLINGER nor ROTATE_SURFACE_FLINGER - // (a.k.a. everyone except WindowManager / tests / Launcher) from setting non rectangle - // preserving transformations. - const bool allowNonRectPreservingTransforms = - permissions & Permission::ROTATE_SURFACE_FLINGER; - if (layer->setMatrix(s.matrix, allowNonRectPreservingTransforms)) flags |= eTraversalNeeded; + if (layer->setMatrix(s.matrix)) flags |= eTraversalNeeded; } if (what & layer_state_t::eTransparentRegionChanged) { if (layer->setTransparentRegionHint(s.transparentRegion)) flags |= eTraversalNeeded; } if (what & layer_state_t::eFlagsChanged) { - auto changedFlags = s.flags; - if (changedFlags & layer_state_t::eLayerIsDisplayDecoration) { - if ((permissions & Permission::INTERNAL_SYSTEM_WINDOW) == 0) { - changedFlags &= ~layer_state_t::eLayerIsDisplayDecoration; - ALOGE("Attempt to use eLayerIsDisplayDecoration without permission " - "INTERNAL_SYSTEM_WINDOW!"); - } - } - if (layer->setFlags(changedFlags, s.mask)) flags |= eTraversalNeeded; + if (layer->setFlags(s.flags, s.mask)) flags |= eTraversalNeeded; } if (what & layer_state_t::eCornerRadiusChanged) { if (layer->setCornerRadius(s.cornerRadius)) @@ -4410,12 +4377,8 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded; } if (what & layer_state_t::eInputInfoChanged) { - if (privileged) { - layer->setInputInfo(*s.windowInfoHandle->getInfo()); - flags |= eTraversalNeeded; - } else { - ALOGE("Attempt to update WindowInfo without permission ACCESS_SURFACE_FLINGER"); - } + layer->setInputInfo(*s.windowInfoHandle->getInfo()); + flags |= eTraversalNeeded; } std::optional dequeueBufferTimestamp; if (what & layer_state_t::eMetadataChanged) { @@ -4439,22 +4402,19 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (layer->setShadowRadius(s.shadowRadius)) flags |= eTraversalNeeded; } if (what & layer_state_t::eFrameRateSelectionPriority) { - if (privileged && layer->setFrameRateSelectionPriority(s.frameRateSelectionPriority)) { + if (layer->setFrameRateSelectionPriority(s.frameRateSelectionPriority)) { flags |= eTraversalNeeded; } } if (what & layer_state_t::eFrameRateChanged) { - if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility, s.changeFrameRateStrategy, - "SurfaceFlinger::setClientStateLocked", privileged)) { - const auto compatibility = - Layer::FrameRate::convertCompatibility(s.frameRateCompatibility); - const auto strategy = - Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy); + const auto compatibility = + Layer::FrameRate::convertCompatibility(s.frameRateCompatibility); + const auto strategy = + Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy); - if (layer->setFrameRate( - Layer::FrameRate(Fps::fromValue(s.frameRate), compatibility, strategy))) { - flags |= eTraversalNeeded; - } + if (layer->setFrameRate( + Layer::FrameRate(Fps::fromValue(s.frameRate), compatibility, strategy))) { + flags |= eTraversalNeeded; } } if (what & layer_state_t::eFixedTransformHintChanged) { @@ -4466,12 +4426,8 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime layer->setAutoRefresh(s.autoRefresh); } if (what & layer_state_t::eTrustedOverlayChanged) { - if (privileged) { - if (layer->setTrustedOverlay(s.isTrustedOverlay)) { - flags |= eTraversalNeeded; - } - } else { - ALOGE("Attempt to set trusted overlay without permission ACCESS_SURFACE_FLINGER"); + if (layer->setTrustedOverlay(s.isTrustedOverlay)) { + flags |= eTraversalNeeded; } } if (what & layer_state_t::eStretchChanged) { @@ -4490,13 +4446,9 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } } if (what & layer_state_t::eDropInputModeChanged) { - if (privileged) { - if (layer->setDropInputMode(s.dropInputMode)) { - flags |= eTraversalNeeded; - mInputInfoChanged = true; - } - } else { - ALOGE("Attempt to update DropInputMode without permission ACCESS_SURFACE_FLINGER"); + if (layer->setDropInputMode(s.dropInputMode)) { + flags |= eTraversalNeeded; + mInputInfoChanged = true; } } // This has to happen after we reparent children because when we reparent to null we remove diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8ca9982b98..a6a17b8bde 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -729,7 +729,7 @@ private: // Returns true if there is at least one transaction that needs to be flushed bool transactionFlushNeeded(); - uint32_t setClientStateLocked(const FrameTimelineInfo&, const ComposerState&, + uint32_t setClientStateLocked(const FrameTimelineInfo&, ComposerState&, int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, uint32_t permissions) REQUIRES(mStateLock); -- cgit v1.2.3-59-g8ed1b From 6fa425a82c0ff753d7bd1b98eef1d70154c54f88 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 16 Dec 2021 07:16:04 -0800 Subject: SF: Calculate WindowInfo frame correctly for all layers The old logic skipped transform calculation using an early return if the layer bounds were invalid. This skipped the calculations which transformed the WindowInfo frame into display space. This also resulted in container layers being misconfigured, since they did not have their input bounds calculated correctly. Allow all layers to have their WindowInfo calculated correctly in display space, even if their input bounds happen to be invalid. Bug: 162194035 Test: atest libgui_test Test: manual Change-Id: I7b3c361bb9a12adf52586d3a940501e4d8a9e667 --- libs/gui/WindowInfo.cpp | 3 +- libs/gui/tests/EndToEndNativeInputTest.cpp | 76 ++++++++++++++++++++++++++++++ services/surfaceflinger/Layer.cpp | 24 +++------- services/surfaceflinger/Layer.h | 13 +++++ 4 files changed, 98 insertions(+), 18 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 8d356aaaa1..1c7b270527 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -52,7 +52,8 @@ bool WindowInfo::interceptsStylus() const { } bool WindowInfo::overlaps(const WindowInfo* other) const { - return frameLeft < other->frameRight && frameRight > other->frameLeft && + const bool nonEmpty = (frameRight - frameLeft > 0) || (frameBottom - frameTop > 0); + return nonEmpty && frameLeft < other->frameRight && frameRight > other->frameLeft && frameTop < other->frameBottom && frameBottom > other->frameTop; } diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 6f1263bb89..83e9858875 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -987,6 +987,82 @@ TEST_F(InputSurfacesTest, drop_input_policy) { EXPECT_EQ(surface->consumeEvent(100), nullptr); } +/** + * If a cropped layer's touchable region is replaced with a null crop, it should receive input in + * its own crop. + */ +TEST_F(InputSurfacesTest, cropped_container_replaces_touchable_region_with_null_crop) { + std::unique_ptr parentContainer = + InputSurface::makeContainerInputSurface(mComposerClient, 0, 0); + std::unique_ptr containerSurface = + InputSurface::makeContainerInputSurface(mComposerClient, 100, 100); + containerSurface->doTransaction( + [&](auto &t, auto &sc) { t.reparent(sc, parentContainer->mSurfaceControl); }); + containerSurface->mInputInfo.replaceTouchableRegionWithCrop = true; + containerSurface->mInputInfo.touchableRegionCropHandle = nullptr; + parentContainer->showAt(10, 10, Rect(0, 0, 20, 20)); + containerSurface->showAt(10, 10, Rect(0, 0, 5, 5)); + + // Receives events inside its own crop + injectTap(21, 21); + containerSurface->expectTap(1, 1); // Event is in layer space + + // Does not receive events outside its crop + injectTap(26, 26); + EXPECT_EQ(containerSurface->consumeEvent(100), nullptr); +} + +/** + * If an un-cropped layer's touchable region is replaced with a null crop, it should receive input + * in its parent's touchable region. The input events should be in the layer's coordinate space. + */ +TEST_F(InputSurfacesTest, uncropped_container_replaces_touchable_region_with_null_crop) { + std::unique_ptr parentContainer = + InputSurface::makeContainerInputSurface(mComposerClient, 0, 0); + std::unique_ptr containerSurface = + InputSurface::makeContainerInputSurface(mComposerClient, 100, 100); + containerSurface->doTransaction( + [&](auto &t, auto &sc) { t.reparent(sc, parentContainer->mSurfaceControl); }); + containerSurface->mInputInfo.replaceTouchableRegionWithCrop = true; + containerSurface->mInputInfo.touchableRegionCropHandle = nullptr; + parentContainer->showAt(10, 10, Rect(0, 0, 20, 20)); + containerSurface->showAt(10, 10, Rect::INVALID_RECT); + + // Receives events inside parent bounds + injectTap(21, 21); + containerSurface->expectTap(1, 1); // Event is in layer space + + // Does not receive events outside parent bounds + injectTap(31, 31); + EXPECT_EQ(containerSurface->consumeEvent(100), nullptr); +} + +/** + * If a layer's touchable region is replaced with a layer crop, it should receive input in the crop + * layer's bounds. The input events should be in the layer's coordinate space. + */ +TEST_F(InputSurfacesTest, replace_touchable_region_with_crop) { + std::unique_ptr cropLayer = + InputSurface::makeContainerInputSurface(mComposerClient, 0, 0); + cropLayer->showAt(50, 50, Rect(0, 0, 20, 20)); + + std::unique_ptr containerSurface = + InputSurface::makeContainerInputSurface(mComposerClient, 100, 100); + containerSurface->mInputInfo.replaceTouchableRegionWithCrop = true; + containerSurface->mInputInfo.touchableRegionCropHandle = + cropLayer->mSurfaceControl->getHandle(); + containerSurface->showAt(10, 10, Rect::INVALID_RECT); + + // Receives events inside crop layer bounds + injectTap(51, 51); + containerSurface->expectTap(41, 41); // Event is in layer space + + // Does not receive events outside crop layer bounds + injectTap(21, 21); + injectTap(71, 71); + EXPECT_EQ(containerSurface->consumeEvent(100), nullptr); +} + class MultiDisplayTests : public InputSurfacesTest { public: MultiDisplayTests() : InputSurfacesTest() { ProcessState::self()->startThreadPool(); } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index fa2c92dd32..5175be9b9d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2167,25 +2167,15 @@ Rect Layer::getInputBounds() const { } void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTransform) { - // Transform layer size to screen space and inset it by surface insets. - // If this is a portal window, set the touchableRegion to the layerBounds. - Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE - ? getInputBounds() - : info.touchableRegion.getBounds(); + Rect layerBounds = getInputBounds(); if (!layerBounds.isValid()) { - layerBounds = getInputBounds(); - } - - if (!layerBounds.isValid()) { - // If the layer bounds is empty, set the frame to empty and clear the transform - info.frameLeft = 0; - info.frameTop = 0; - info.frameRight = 0; - info.frameBottom = 0; - info.transform.reset(); - info.touchableRegion = Region(); info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE; - return; + info.touchableRegion.clear(); + // A layer could have invalid input bounds and still expect to receive touch input if it has + // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated + // correctly to determine the coordinate space for input events. Use an empty rect so that + // the layer will receive input in its own layer space. + layerBounds = Rect::EMPTY_RECT; } const ui::Transform layerTransform = getInputTransform(); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4cdd8fa24b..9e10b4f02f 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -959,6 +959,19 @@ protected: bool usingRelativeZ(LayerVector::StateSet) const; virtual ui::Transform getInputTransform() const; + /** + * Get the bounds in layer space within which this layer can receive input. + * + * These bounds are used to: + * - Determine the input frame for the layer to be used for occlusion detection; and + * - Determine the coordinate space within which the layer will receive input. The top-left of + * this rect will be the origin of the coordinate space that the input events sent to the + * layer will be in (prior to accounting for surface insets). + * + * The layer can still receive touch input if these bounds are invalid if + * "replaceTouchableRegionWithCrop" is specified. In this case, the layer will receive input + * in this layer's space, regardless of the specified crop layer. + */ virtual Rect getInputBounds() const; // constant -- cgit v1.2.3-59-g8ed1b From 8c2859824db8f602a72ceff458f4374e6faf0a2a Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 28 Jan 2022 09:19:39 -0800 Subject: SF: Enforce that layers with invalid input bounds are not focusable Bug: 162194035 Test: atest libgui_test Change-Id: Ic561e8b3e52faae28888ef3d323583e09aa278c0 --- libs/gui/tests/EndToEndNativeInputTest.cpp | 25 +++++++++++++++++++++++++ services/surfaceflinger/Layer.cpp | 1 + 2 files changed, 26 insertions(+) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 83e9858875..76844d2d83 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -987,6 +987,31 @@ TEST_F(InputSurfacesTest, drop_input_policy) { EXPECT_EQ(surface->consumeEvent(100), nullptr); } +TEST_F(InputSurfacesTest, layer_with_empty_crop_cannot_be_focused) { + std::unique_ptr bufferSurface = + InputSurface::makeBufferInputSurface(mComposerClient, 100, 100); + + bufferSurface->showAt(50, 50, Rect::EMPTY_RECT); + + bufferSurface->requestFocus(); + EXPECT_EQ(bufferSurface->consumeEvent(100), nullptr); + + bufferSurface->showAt(50, 50, Rect::INVALID_RECT); + + bufferSurface->requestFocus(); + EXPECT_EQ(bufferSurface->consumeEvent(100), nullptr); +} + +TEST_F(InputSurfacesTest, layer_with_valid_crop_can_be_focused) { + std::unique_ptr bufferSurface = + InputSurface::makeBufferInputSurface(mComposerClient, 100, 100); + + bufferSurface->showAt(50, 50, Rect{0, 0, 100, 100}); + + bufferSurface->requestFocus(); + bufferSurface->assertFocusChange(true); +} + /** * If a cropped layer's touchable region is replaced with a null crop, it should receive input in * its own crop. diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5175be9b9d..8c77a8b648 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2170,6 +2170,7 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTra Rect layerBounds = getInputBounds(); if (!layerBounds.isValid()) { info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE; + info.focusable = false; info.touchableRegion.clear(); // A layer could have invalid input bounds and still expect to receive touch input if it has // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated -- cgit v1.2.3-59-g8ed1b From c9589c17c0394b8ae9c738a8bdb3daa057ed4f9c Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Wed, 22 Sep 2021 06:11:43 -0700 Subject: SF: Clean up input info calculations This CL simplifies the calculation of the input transform and frame for Layers. It also switches the calculations to use floats rather than intergers for greater precesion when scaling. Bug: 200787840 Bug: 179274888 Test: atest libgui_test Change-Id: Ia1ed53b669caa867e5b98e72d5d71ed615222f8f --- libs/gui/tests/EndToEndNativeInputTest.cpp | 7 +- services/surfaceflinger/Layer.cpp | 137 ++++++++++++----------------- services/surfaceflinger/Layer.h | 2 +- 3 files changed, 64 insertions(+), 82 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 76844d2d83..06a0acae49 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -546,7 +546,10 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets) { } TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) { + std::unique_ptr bgSurface = makeSurface(100, 100); std::unique_ptr fgSurface = makeSurface(100, 100); + bgSurface->showAt(100, 100); + // In case we pass the very big inset without any checking. fgSurface->mInputInfo.surfaceInset = INT32_MAX; fgSurface->showAt(100, 100); @@ -554,8 +557,8 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) { fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); }); // expect no crash for overflow, and inset size to be clamped to surface size - injectTap(202, 202); - fgSurface->expectTap(1, 1); + injectTap(112, 124); + bgSurface->expectTap(12, 24); } // Ensure we ignore transparent region when getting screen bounds when positioning input frame. diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 8c77a8b648..fc73181c87 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2166,9 +2166,9 @@ Rect Layer::getInputBounds() const { return getCroppedBufferSize(getDrawingState()); } -void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTransform) { - Rect layerBounds = getInputBounds(); - if (!layerBounds.isValid()) { +void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) { + Rect tmpBounds = getInputBounds(); + if (!tmpBounds.isValid()) { info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE; info.focusable = false; info.touchableRegion.clear(); @@ -2176,82 +2176,61 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTra // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated // correctly to determine the coordinate space for input events. Use an empty rect so that // the layer will receive input in its own layer space. - layerBounds = Rect::EMPTY_RECT; - } - - const ui::Transform layerTransform = getInputTransform(); - // Transform that takes window coordinates to non-rotated display coordinates - ui::Transform t = displayTransform * layerTransform; - int32_t xSurfaceInset = info.surfaceInset; - int32_t ySurfaceInset = info.surfaceInset; - // Bring screenBounds into non-unrotated space - Rect screenBounds = displayTransform.transform(Rect{mScreenBounds}); - - const float xScale = t.getScaleX(); - const float yScale = t.getScaleY(); - if (xScale != 1.0f || yScale != 1.0f) { - xSurfaceInset = std::round(xSurfaceInset * xScale); - ySurfaceInset = std::round(ySurfaceInset * yScale); - } - - // Transform the layer bounds from layer coordinate space to display coordinate space. - Rect transformedLayerBounds = t.transform(layerBounds); - - // clamp inset to layer bounds - xSurfaceInset = (xSurfaceInset >= 0) - ? std::min(xSurfaceInset, transformedLayerBounds.getWidth() / 2) - : 0; - ySurfaceInset = (ySurfaceInset >= 0) - ? std::min(ySurfaceInset, transformedLayerBounds.getHeight() / 2) - : 0; - - // inset while protecting from overflow TODO(b/161235021): What is going wrong - // in the overflow scenario? - { - int32_t tmp; - if (!__builtin_add_overflow(transformedLayerBounds.left, xSurfaceInset, &tmp)) - transformedLayerBounds.left = tmp; - if (!__builtin_sub_overflow(transformedLayerBounds.right, xSurfaceInset, &tmp)) - transformedLayerBounds.right = tmp; - if (!__builtin_add_overflow(transformedLayerBounds.top, ySurfaceInset, &tmp)) - transformedLayerBounds.top = tmp; - if (!__builtin_sub_overflow(transformedLayerBounds.bottom, ySurfaceInset, &tmp)) - transformedLayerBounds.bottom = tmp; - } - - // Compute the correct transform to send to input. This will allow it to transform the - // input coordinates from display space into window space. Therefore, it needs to use the - // final layer frame to create the inverse transform. Since surface insets are added later, - // along with the overflow, the best way to ensure we get the correct transform is to use - // the final frame calculated. - // 1. Take the original transform set on the window and get the inverse transform. This is - // used to get the final bounds in display space (ignorning the transform). Apply the - // inverse transform on the layerBounds to get the untransformed frame (in layer space) - // 2. Take the top and left of the untransformed frame to get the real position on screen. - // Apply the layer transform on top/left so it includes any scale or rotation. These will - // be the new translation values for the transform. - // 3. Update the translation of the original transform to the new translation values. - // 4. Send the inverse transform to input so the coordinates can be transformed back into - // window space. - ui::Transform inverseTransform = t.inverse(); - Rect nonTransformedBounds = inverseTransform.transform(transformedLayerBounds); - vec2 translation = t.transform(nonTransformedBounds.left, nonTransformedBounds.top); - ui::Transform inputTransform(t); - inputTransform.set(translation.x, translation.y); - info.transform = inputTransform.inverse(); - - // We need to send the layer bounds cropped to the screenbounds since the layer can be cropped. - // The frame should be the area the user sees on screen since it's used for occlusion - // detection. - transformedLayerBounds.intersect(screenBounds, &transformedLayerBounds); - info.frameLeft = transformedLayerBounds.left; - info.frameTop = transformedLayerBounds.top; - info.frameRight = transformedLayerBounds.right; - info.frameBottom = transformedLayerBounds.bottom; - - // Position the touchable region relative to frame screen location and restrict it to frame - // bounds. - info.touchableRegion = inputTransform.transform(info.touchableRegion); + tmpBounds = Rect::EMPTY_RECT; + } + + // InputDispatcher works in the display device's coordinate space. Here, we calculate the + // frame and transform used for the layer, which determines the bounds and the coordinate space + // within which the layer will receive input. + // + // The coordinate space within which each of the bounds are specified is explicitly documented + // in the variable name. For example "inputBoundsInLayer" is specified in layer space. A + // Transform converts one coordinate space to another, which is apparent in its naming. For + // example, "layerToDisplay" transforms layer space to display space. + // + // Coordinate space definitions: + // - display: The display device's coordinate space. Correlates to pixels on the display. + // - screen: The post-rotation coordinate space for the display, a.k.a. logical display space. + // - layer: The coordinate space of this layer. + // - input: The coordinate space in which this layer will receive input events. This could be + // different than layer space if a surfaceInset is used, which changes the origin + // of the input space. + const FloatRect inputBoundsInLayer = tmpBounds.toFloatRect(); + + // Clamp surface inset to the input bounds. + const auto surfaceInset = static_cast(info.surfaceInset); + const float xSurfaceInset = + std::max(0.f, std::min(surfaceInset, inputBoundsInLayer.getWidth() / 2.f)); + const float ySurfaceInset = + std::max(0.f, std::min(surfaceInset, inputBoundsInLayer.getHeight() / 2.f)); + + // Apply the insets to the input bounds. + const FloatRect insetBoundsInLayer(inputBoundsInLayer.left + xSurfaceInset, + inputBoundsInLayer.top + ySurfaceInset, + inputBoundsInLayer.right - xSurfaceInset, + inputBoundsInLayer.bottom - ySurfaceInset); + + // Crop the input bounds to ensure it is within the parent's bounds. + const FloatRect croppedInsetBoundsInLayer = mBounds.intersect(insetBoundsInLayer); + + const ui::Transform layerToScreen = getInputTransform(); + const ui::Transform layerToDisplay = screenToDisplay * layerToScreen; + + const Rect roundedFrameInDisplay{layerToDisplay.transform(croppedInsetBoundsInLayer)}; + info.frameLeft = roundedFrameInDisplay.left; + info.frameTop = roundedFrameInDisplay.top; + info.frameRight = roundedFrameInDisplay.right; + info.frameBottom = roundedFrameInDisplay.bottom; + + ui::Transform inputToLayer; + inputToLayer.set(insetBoundsInLayer.left, insetBoundsInLayer.top); + const ui::Transform inputToDisplay = layerToDisplay * inputToLayer; + + // InputDispatcher expects a display-to-input transform. + info.transform = inputToDisplay.inverse(); + + // The touchable region is specified in the input coordinate space. Change it to display space. + info.touchableRegion = inputToDisplay.transform(info.touchableRegion); } void Layer::fillTouchOcclusionMode(WindowInfo& info) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 9e10b4f02f..3fecdeca79 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -1093,7 +1093,7 @@ private: void fillTouchOcclusionMode(gui::WindowInfo& info); // Fills in the frame and transform info for the gui::WindowInfo. - void fillInputFrameInfo(gui::WindowInfo&, const ui::Transform& displayTransform); + void fillInputFrameInfo(gui::WindowInfo&, const ui::Transform& screenToDisplay); // Cached properties computed from drawing state // Effective transform taking into account parent transforms and any parent scaling, which is -- cgit v1.2.3-59-g8ed1b From 1b700199c9f0d7169fd4598d8efaac2ab80c4a30 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 4 Feb 2022 10:09:47 -0800 Subject: SF: Remove layer mRefreshPending tracking This flag was used to ensure we do not latch a second buffer without going through the composition stage. This flag is not needed because if we latch a buffer, then we are guaranteed to go into the composition stage. Incentive for this change: to rebuild the layer state, via layertracegenerator, we invoke the commit stage over and over again. This flag prevents us from latching another buffer because the tool does not call composite. Test: presubmit, also presubmit with fatal log if we ever try to latch when mRefreshPending is true (ag/16790650) Bug: 200284593 Change-Id: I332349865b19ae7a205002167f26f5a2f76688af --- libs/gui/LayerDebugInfo.cpp | 5 +---- libs/gui/include/gui/LayerDebugInfo.h | 1 - services/surfaceflinger/BufferLayer.cpp | 16 ---------------- services/surfaceflinger/BufferLayer.h | 6 ------ services/surfaceflinger/Layer.cpp | 2 -- services/surfaceflinger/Layer.h | 2 -- services/surfaceflinger/SurfaceFlinger.cpp | 4 +--- services/surfaceflinger/layerproto/LayerProtoParser.cpp | 2 +- 8 files changed, 3 insertions(+), 35 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp index 0827bbe3ee..ea5fb293a6 100644 --- a/libs/gui/LayerDebugInfo.cpp +++ b/libs/gui/LayerDebugInfo.cpp @@ -58,7 +58,6 @@ status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const { RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferStride)); RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferFormat)); RETURN_ON_ERROR(parcel->writeInt32(mNumQueuedFrames)); - RETURN_ON_ERROR(parcel->writeBool(mRefreshPending)); RETURN_ON_ERROR(parcel->writeBool(mIsOpaque)); RETURN_ON_ERROR(parcel->writeBool(mContentDirty)); RETURN_ON_ERROR(parcel->write(mStretchEffect)); @@ -103,7 +102,6 @@ status_t LayerDebugInfo::readFromParcel(const Parcel* parcel) { RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferStride)); RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferFormat)); RETURN_ON_ERROR(parcel->readInt32(&mNumQueuedFrames)); - RETURN_ON_ERROR(parcel->readBool(&mRefreshPending)); RETURN_ON_ERROR(parcel->readBool(&mIsOpaque)); RETURN_ON_ERROR(parcel->readBool(&mContentDirty)); RETURN_ON_ERROR(parcel->read(mStretchEffect)); @@ -146,8 +144,7 @@ std::string to_string(const LayerDebugInfo& info) { StringAppendF(&result, " activeBuffer=[%4ux%4u:%4u,%s],", info.mActiveBufferWidth, info.mActiveBufferHeight, info.mActiveBufferStride, decodePixelFormat(info.mActiveBufferFormat).c_str()); - StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d", info.mNumQueuedFrames, - info.mRefreshPending); + StringAppendF(&result, " queued-frames=%d", info.mNumQueuedFrames); result.append("\n"); return result; } diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h index 8b7d32c0a5..af834d78df 100644 --- a/libs/gui/include/gui/LayerDebugInfo.h +++ b/libs/gui/include/gui/LayerDebugInfo.h @@ -64,7 +64,6 @@ public: int32_t mActiveBufferStride = 0; PixelFormat mActiveBufferFormat = PIXEL_FORMAT_NONE; int32_t mNumQueuedFrames = -1; - bool mRefreshPending = false; bool mIsOpaque = false; bool mContentDirty = false; StretchEffect mStretchEffect = {}; diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index b7e2ff3b34..18a6baeffe 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -319,7 +319,6 @@ bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) { Mutex::Autolock lock(mFrameEventHistoryMutex); mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime); } - mRefreshPending = false; return hasReadyFrame(); } namespace { @@ -474,19 +473,6 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, return refreshRequired; } - if (!hasReadyFrame()) { - return false; - } - - // if we've already called updateTexImage() without going through - // a composition step, we have to skip this layer at this point - // because we cannot call updateTeximage() without a corresponding - // compositionComplete() call. - // we'll trigger an update in onPreComposition(). - if (mRefreshPending) { - return false; - } - // If the head buffer's acquire fence hasn't signaled yet, return and // try again later if (!fenceHasSignaled()) { @@ -518,7 +504,6 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, gatherBufferInfo(); - mRefreshPending = true; if (oldBufferInfo.mBuffer == nullptr) { // the first time we receive a buffer, we need to trigger a // geometry invalidation. @@ -689,7 +674,6 @@ FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const } void BufferLayer::latchAndReleaseBuffer() { - mRefreshPending = false; if (hasReadyFrame()) { bool ignored = false; latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */); diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 99267be673..3e70493101 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -88,9 +88,6 @@ public: // to figure out if the content or size of a surface has changed. bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, nsecs_t expectedPresentTime) override; - - bool isBufferLatched() const override { return mRefreshPending; } - bool hasReadyFrame() const override; // Returns the current scaling mode @@ -158,9 +155,6 @@ protected: // from graphics API const uint32_t mTextureName; - - bool mRefreshPending{false}; - ui::Dataspace translateDataspace(ui::Dataspace dataspace); void setInitialValuesForClone(const sp& clonedFrom); void updateCloneBufferInfo() override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 645d4d1b44..a039250327 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1398,7 +1398,6 @@ LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const { } } info.mNumQueuedFrames = getQueuedFrameCount(); - info.mRefreshPending = isBufferLatched(); info.mIsOpaque = isOpaque(ds); info.mContentDirty = contentDirty; info.mStretchEffect = getStretchEffect(); @@ -2029,7 +2028,6 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, layerInfo->set_is_protected(isProtected()); layerInfo->set_dataspace(dataspaceDetails(static_cast(getDataSpace()))); layerInfo->set_queued_frames(getQueuedFrameCount()); - layerInfo->set_refresh_pending(isBufferLatched()); layerInfo->set_curr_frame(mCurrentFrameNumber); layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 605a27efa7..ddcd641461 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -549,8 +549,6 @@ public: return false; } - virtual bool isBufferLatched() const { return false; } - virtual void latchAndReleaseBuffer() {} /* diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3459a8ff5b..d5f340b1f0 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3563,11 +3563,9 @@ bool SurfaceFlinger::latchBuffers() { for (const auto& layer : mLayersWithQueuedFrames) { if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) { mLayersPendingRefresh.push_back(layer); - } - layer->useSurfaceDamage(); - if (layer->isBufferLatched()) { newDataLatched = true; } + layer->useSurfaceDamage(); } } diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp index 2841f7c2fd..854084e7f9 100644 --- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp +++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp @@ -305,7 +305,7 @@ std::string LayerProtoParser::Layer::to_string() const { zOrderRelativeOf == nullptr ? "none" : zOrderRelativeOf->name.c_str()); StringAppendF(&result, " activeBuffer=%s,", activeBuffer.to_string().c_str()); StringAppendF(&result, " tr=%s", bufferTransform.to_string().c_str()); - StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d,", queuedFrames, refreshPending); + StringAppendF(&result, " queued-frames=%d", queuedFrames); StringAppendF(&result, " metadata={"); bool first = true; for (const auto& entry : metadata.mMap) { -- cgit v1.2.3-59-g8ed1b From 4d5c52ff1615c8cbcfe2f5209884245bba711e7c Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 31 Jan 2022 08:52:10 -0800 Subject: Introduce WindowInfo::InputConfig flag to control input behavior Instead of re-using layoutParams flags and layoutParam types and having redundant information in WindowInfo, we add a new InputConfig flag that the native input pipeline will use for all input window configurations. This also reduces WindowInfo's size by converting booleans into flags. Bug: 216806304 Test: atest libgui_test Test: atest inputflinger_tests Change-Id: If0354cc2cfc84986f7f0d48cd9348be1ff82293d --- libs/gui/WindowInfo.cpp | 59 ++--- libs/gui/include/gui/WindowInfo.h | 48 +++- libs/gui/tests/EndToEndNativeInputTest.cpp | 25 +-- libs/gui/tests/WindowInfo_test.cpp | 18 +- .../benchmarks/InputDispatcher_benchmarks.cpp | 5 - services/inputflinger/dispatcher/FocusResolver.cpp | 4 +- .../inputflinger/dispatcher/InputDispatcher.cpp | 88 ++++---- services/inputflinger/dispatcher/TouchState.cpp | 6 +- services/inputflinger/tests/FocusResolver_test.cpp | 12 +- .../inputflinger/tests/InputDispatcher_test.cpp | 241 ++++++++++++--------- services/surfaceflinger/Layer.cpp | 17 +- services/surfaceflinger/LayerProtoHelper.cpp | 11 +- .../Tracing/TransactionProtoParser.cpp | 23 +- 13 files changed, 320 insertions(+), 237 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index a8667867b2..2c25e7e2ac 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -18,7 +18,6 @@ #define LOG_TAG "WindowInfo" #define LOG_NDEBUG 0 -#include #include #include @@ -27,6 +26,14 @@ namespace android::gui { // --- WindowInfo --- +void WindowInfo::setInputConfig(Flags config, bool value) { + if (value) { + inputConfig |= config; + return; + } + inputConfig &= ~config; +} + void WindowInfo::addTouchableRegion(const Rect& region) { touchableRegion.orSelf(region); } @@ -40,7 +47,7 @@ bool WindowInfo::frameContainsPoint(int32_t x, int32_t y) const { } bool WindowInfo::supportsSplitTouch() const { - return flags.test(Flag::SPLIT_TOUCH); + return inputConfig.test(InputConfig::SPLIT_TOUCH); } bool WindowInfo::isSpy() const { @@ -58,20 +65,19 @@ bool WindowInfo::overlaps(const WindowInfo* other) const { } bool WindowInfo::operator==(const WindowInfo& info) const { - return info.token == token && info.id == id && info.name == name && info.flags == flags && - info.type == type && info.dispatchingTimeout == dispatchingTimeout && - info.frameLeft == frameLeft && info.frameTop == frameTop && - info.frameRight == frameRight && info.frameBottom == frameBottom && - info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor && - info.transform == transform && info.touchableRegion.hasSameRects(touchableRegion) && - info.visible == visible && info.trustedOverlay == trustedOverlay && - info.focusable == focusable && info.touchOcclusionMode == touchOcclusionMode && - info.hasWallpaper == hasWallpaper && info.paused == paused && - info.ownerPid == ownerPid && info.ownerUid == ownerUid && - info.packageName == packageName && info.inputFeatures == inputFeatures && + return info.token == token && info.id == id && info.name == name && + info.dispatchingTimeout == dispatchingTimeout && info.frameLeft == frameLeft && + info.frameTop == frameTop && info.frameRight == frameRight && + info.frameBottom == frameBottom && info.surfaceInset == surfaceInset && + info.globalScaleFactor == globalScaleFactor && info.transform == transform && + info.touchableRegion.hasSameRects(touchableRegion) && + info.touchOcclusionMode == touchOcclusionMode && info.ownerPid == ownerPid && + info.ownerUid == ownerUid && info.packageName == packageName && + info.inputFeatures == inputFeatures && info.inputConfig == inputConfig && info.displayId == displayId && info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && - info.applicationInfo == applicationInfo; + info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType && + info.layoutParamsFlags == layoutParamsFlags; } status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { @@ -85,13 +91,18 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { } parcel->writeInt32(1); + // Ensure that the size of the flags that we use is 32 bits for writing into the parcel. + static_assert(sizeof(inputFeatures) == 4u); + static_assert(sizeof(inputConfig) == 4u); + // clang-format off status_t status = parcel->writeStrongBinder(token) ?: parcel->writeInt64(dispatchingTimeout.count()) ?: parcel->writeInt32(id) ?: parcel->writeUtf8AsUtf16(name) ?: - parcel->writeInt32(flags.get()) ?: - parcel->writeInt32(static_cast>(type)) ?: + parcel->writeInt32(layoutParamsFlags.get()) ?: + parcel->writeInt32( + static_cast>(layoutParamsType)) ?: parcel->writeInt32(frameLeft) ?: parcel->writeInt32(frameTop) ?: parcel->writeInt32(frameRight) ?: @@ -105,16 +116,12 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeFloat(transform.dtdy()) ?: parcel->writeFloat(transform.dsdy()) ?: parcel->writeFloat(transform.ty()) ?: - parcel->writeBool(visible) ?: - parcel->writeBool(focusable) ?: - parcel->writeBool(hasWallpaper) ?: - parcel->writeBool(paused) ?: - parcel->writeBool(trustedOverlay) ?: parcel->writeInt32(static_cast(touchOcclusionMode)) ?: parcel->writeInt32(ownerPid) ?: parcel->writeInt32(ownerUid) ?: parcel->writeUtf8AsUtf16(packageName) ?: parcel->writeInt32(inputFeatures.get()) ?: + parcel->writeInt32(inputConfig.get()) ?: parcel->writeInt32(displayId) ?: applicationInfo.writeToParcel(parcel) ?: parcel->write(touchableRegion) ?: @@ -141,8 +148,8 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { return status; } - flags = Flags(parcel->readInt32()); - type = static_cast(parcel->readInt32()); + layoutParamsFlags = Flags(parcel->readInt32()); + layoutParamsType = static_cast(parcel->readInt32()); float dsdx, dtdx, tx, dtdy, dsdy, ty; int32_t touchOcclusionModeInt; // clang-format off @@ -159,11 +166,6 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->readFloat(&dtdy) ?: parcel->readFloat(&dsdy) ?: parcel->readFloat(&ty) ?: - parcel->readBool(&visible) ?: - parcel->readBool(&focusable) ?: - parcel->readBool(&hasWallpaper) ?: - parcel->readBool(&paused) ?: - parcel->readBool(&trustedOverlay) ?: parcel->readInt32(&touchOcclusionModeInt) ?: parcel->readInt32(&ownerPid) ?: parcel->readInt32(&ownerUid) ?: @@ -177,6 +179,7 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { touchOcclusionMode = static_cast(touchOcclusionModeInt); inputFeatures = Flags(parcel->readInt32()); + inputConfig = Flags(parcel->readInt32()); // clang-format off status = parcel->readInt32(&displayId) ?: applicationInfo.readFromParcel(parcel) ?: diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index eb64ac9b25..1b3419a25b 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -151,6 +151,34 @@ struct WindowInfo : public Parcelable { // clang-format on }; + // Flags used to determine configuration of this input window. + // Input windows can be configured with two sets of flags: InputFeature (WindowInfo::Feature + // defined above), and InputConfig. When adding a new configuration for an input window: + // - If you are adding a new flag that's visible and accessible to apps, it should be added + // as an InputFeature. + // - If you are adding an internal behaviour that is used within the system or shell and is + // not exposed to apps, it should be added as an InputConfig. + enum class InputConfig : uint32_t { + // clang-format off + NONE = 0, + NOT_VISIBLE = 1 << 0, + NOT_FOCUSABLE = 1 << 1, + NOT_TOUCHABLE = 1 << 2, + NOT_TOUCH_MODAL = 1 << 3, + SPLIT_TOUCH = 1 << 4, + DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 5, + IS_WALLPAPER = 1 << 6, + PAUSE_DISPATCHING = 1 << 7, + // This flag is set when the window is of a trusted type that is allowed to silently + // overlay other windows for the purpose of implementing the secure views feature. + // Trusted overlays, such as IME windows, can partly obscure other windows without causing + // motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. + TRUSTED_OVERLAY = 1 << 8, + WATCH_OUTSIDE_TOUCH = 1 << 9, + SLIPPERY = 1 << 10, + // clang-format on + }; + /* These values are filled in by the WM and passed through SurfaceFlinger * unless specified otherwise. */ @@ -164,8 +192,6 @@ struct WindowInfo : public Parcelable { // This uniquely identifies the input window. int32_t id = -1; std::string name; - Flags flags; - Type type = Type::UNKNOWN; std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5); /* These values are filled in by SurfaceFlinger. */ @@ -198,26 +224,24 @@ struct WindowInfo : public Parcelable { * to absolute coordinates by SurfaceFlinger once the frame is computed. */ Region touchableRegion; - bool visible = false; - bool focusable = false; - bool hasWallpaper = false; - bool paused = false; - /* This flag is set when the window is of a trusted type that is allowed to silently - * overlay other windows for the purpose of implementing the secure views feature. - * Trusted overlays, such as IME windows, can partly obscure other windows without causing - * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - */ - bool trustedOverlay = false; + TouchOcclusionMode touchOcclusionMode = TouchOcclusionMode::BLOCK_UNTRUSTED; int32_t ownerPid = -1; int32_t ownerUid = -1; std::string packageName; Flags inputFeatures; + Flags inputConfig; int32_t displayId = ADISPLAY_ID_NONE; InputApplicationInfo applicationInfo; bool replaceTouchableRegionWithCrop = false; wp touchableRegionCropHandle; + // The window's layout params flags and type set by WM. + Type layoutParamsType = Type::UNKNOWN; + Flags layoutParamsFlags; + + void setInputConfig(Flags config, bool value); + void addTouchableRegion(const Rect& region); bool touchableRegionContainsPoint(int32_t x, int32_t y) const; diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 06a0acae49..1151aa3f0f 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -266,13 +266,10 @@ private: void populateInputInfo(int width, int height) { mInputInfo.token = mClientChannel->getConnectionToken(); mInputInfo.name = "Test info"; - mInputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL; - mInputInfo.type = WindowInfo::Type::BASE_APPLICATION; mInputInfo.dispatchingTimeout = 5s; mInputInfo.globalScaleFactor = 1.0; - mInputInfo.focusable = true; - mInputInfo.hasWallpaper = false; - mInputInfo.paused = false; + mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCH_MODAL, true); + mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, false); mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height)); @@ -750,7 +747,7 @@ TEST_F(InputSurfacesTest, touch_flag_obscured) { // Add non touchable window to fully cover touchable window. Window behind gets touch, but // with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED std::unique_ptr nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); nonTouchableSurface->mInputInfo.ownerUid = 22222; // Overriding occlusion mode otherwise the touch would be discarded at InputDispatcher by // the default obscured/untrusted touch filter introduced in S. @@ -770,8 +767,8 @@ TEST_F(InputSurfacesTest, touch_flag_partially_obscured_with_crop) { // AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED std::unique_ptr parentSurface = makeSurface(100, 100); std::unique_ptr nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; - parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); + parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); nonTouchableSurface->mInputInfo.ownerUid = 22222; parentSurface->mInputInfo.ownerUid = 22222; nonTouchableSurface->showAt(0, 0); @@ -794,8 +791,8 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_crop) { // the touchable window. Window behind gets touch with no obscured flags. std::unique_ptr parentSurface = makeSurface(100, 100); std::unique_ptr nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; - parentSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); + parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); nonTouchableSurface->mInputInfo.ownerUid = 22222; parentSurface->mInputInfo.ownerUid = 22222; nonTouchableSurface->showAt(0, 0); @@ -815,7 +812,7 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_bql) { std::unique_ptr bufferSurface = InputSurface::makeBufferInputSurface(mComposerClient, 0, 0); - bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); bufferSurface->mInputInfo.ownerUid = 22222; surface->showAt(10, 10); @@ -830,7 +827,7 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) { std::unique_ptr bufferSurface = BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0); - bufferSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); bufferSurface->mInputInfo.ownerUid = 22222; surface->showAt(10, 10); @@ -883,7 +880,7 @@ TEST_F(InputSurfacesTest, strict_unobscured_input_obscured_window) { [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); surface->showAt(100, 100); std::unique_ptr obscuringSurface = makeSurface(100, 100); - obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); obscuringSurface->mInputInfo.ownerUid = 22222; obscuringSurface->showAt(100, 100); injectTap(101, 101); @@ -902,7 +899,7 @@ TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) { [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); surface->showAt(100, 100); std::unique_ptr obscuringSurface = makeSurface(100, 100); - obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE; + obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); obscuringSurface->mInputInfo.ownerUid = 22222; obscuringSurface->showAt(190, 190); diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index ff3ba2aae0..ff9bae2800 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -49,8 +49,8 @@ TEST(WindowInfo, Parcelling) { i.windowToken = new BBinder(); i.id = 1; i.name = "Foobar"; - i.flags = WindowInfo::Flag::SLIPPERY; - i.type = WindowInfo::Type::INPUT_METHOD; + i.layoutParamsFlags = WindowInfo::Flag::SLIPPERY; + i.layoutParamsType = WindowInfo::Type::INPUT_METHOD; i.dispatchingTimeout = 12s; i.frameLeft = 93; i.frameTop = 34; @@ -60,15 +60,12 @@ TEST(WindowInfo, Parcelling) { i.globalScaleFactor = 0.3; i.alpha = 0.7; i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1}); - i.visible = false; - i.focusable = false; - i.hasWallpaper = false; - i.paused = false; i.touchOcclusionMode = TouchOcclusionMode::ALLOW; i.ownerPid = 19; i.ownerUid = 24; i.packageName = "com.example.package"; i.inputFeatures = WindowInfo::Feature::DISABLE_USER_ACTIVITY; + i.inputConfig = WindowInfo::InputConfig::NOT_FOCUSABLE; i.displayId = 34; i.replaceTouchableRegionWithCrop = true; i.touchableRegionCropHandle = touchableRegionCropHandle; @@ -85,8 +82,8 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.windowToken, i2.windowToken); ASSERT_EQ(i.id, i2.id); ASSERT_EQ(i.name, i2.name); - ASSERT_EQ(i.flags, i2.flags); - ASSERT_EQ(i.type, i2.type); + ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags); + ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType); ASSERT_EQ(i.dispatchingTimeout, i2.dispatchingTimeout); ASSERT_EQ(i.frameLeft, i2.frameLeft); ASSERT_EQ(i.frameTop, i2.frameTop); @@ -96,15 +93,12 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor); ASSERT_EQ(i.alpha, i2.alpha); ASSERT_EQ(i.transform, i2.transform); - ASSERT_EQ(i.visible, i2.visible); - ASSERT_EQ(i.focusable, i2.focusable); - ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper); - ASSERT_EQ(i.paused, i2.paused); ASSERT_EQ(i.touchOcclusionMode, i2.touchOcclusionMode); ASSERT_EQ(i.ownerPid, i2.ownerPid); ASSERT_EQ(i.ownerUid, i2.ownerUid); ASSERT_EQ(i.packageName, i2.packageName); ASSERT_EQ(i.inputFeatures, i2.inputFeatures); + ASSERT_EQ(i.inputConfig, i2.inputConfig); ASSERT_EQ(i.displayId, i2.displayId); ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop); ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle); diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index 41e9ce2e41..cd20a646a7 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -193,7 +193,6 @@ public: void updateInfo() { mInfo.token = mClientChannel->getConnectionToken(); mInfo.name = "FakeWindowHandle"; - mInfo.type = WindowInfo::Type::APPLICATION; mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; mInfo.frameLeft = mFrame.left; mInfo.frameTop = mFrame.top; @@ -202,10 +201,6 @@ public: mInfo.globalScaleFactor = 1.0; mInfo.touchableRegion.clear(); mInfo.addTouchableRegion(mFrame); - mInfo.visible = true; - mInfo.focusable = true; - mInfo.hasWallpaper = false; - mInfo.paused = false; mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = ADISPLAY_ID_DEFAULT; diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp index 600f02ba80..a02b3e8779 100644 --- a/services/inputflinger/dispatcher/FocusResolver.cpp +++ b/services/inputflinger/dispatcher/FocusResolver.cpp @@ -148,11 +148,11 @@ FocusResolver::Focusability FocusResolver::isTokenFocusable( continue; } windowFound = true; - if (window->getInfo()->visible) { + if (!window->getInfo()->inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE)) { // Check if at least a single window is visible. visibleWindowFound = true; } - if (!window->getInfo()->focusable) { + if (window->getInfo()->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE)) { // Check if all windows with the window token are focusable. allWindowsAreFocusable = false; break; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 6c321bcedd..001c50f533 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -500,16 +500,17 @@ bool isUserActivityEvent(const EventEntry& eventEntry) { // Returns true if the given window can accept pointer events at the given display location. bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y, bool isStylus) { - if (windowInfo.displayId != displayId || !windowInfo.visible) { + const auto inputConfig = windowInfo.inputConfig; + if (windowInfo.displayId != displayId || + inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) { return false; } - const auto flags = windowInfo.flags; const bool windowCanInterceptTouch = isStylus && windowInfo.interceptsStylus(); - if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE) && !windowCanInterceptTouch) { + if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) { return false; } - const bool isModalWindow = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) && - !flags.test(WindowInfo::Flag::NOT_TOUCH_MODAL); + const bool isModalWindow = !inputConfig.test(WindowInfo::InputConfig::NOT_FOCUSABLE) && + !inputConfig.test(WindowInfo::InputConfig::NOT_TOUCH_MODAL); if (!isModalWindow && !windowInfo.touchableRegionContainsPoint(x, y)) { return false; } @@ -1047,7 +1048,8 @@ sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayI return windowHandle; } - if (addOutsideTargets && info.flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) { + if (addOutsideTargets && + info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) { touchState->addOrUpdateWindow(windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0)); } @@ -1900,7 +1902,8 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( return InputEventInjectionResult::PERMISSION_DENIED; } - if (focusedWindowHandle->getInfo()->paused) { + if (focusedWindowHandle->getInfo()->inputConfig.test( + WindowInfo::InputConfig::PAUSE_DISPATCHING)) { ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str()); return InputEventInjectionResult::PENDING; } @@ -2101,7 +2104,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( for (const sp& windowHandle : newTouchedWindows) { const WindowInfo& info = *windowHandle->getInfo(); - if (info.paused) { + if (info.inputConfig.test(WindowInfo::InputConfig::PAUSE_DISPATCHING)) { ALOGI("Not sending touch event to %s because it is paused", windowHandle->getName().c_str()); continue; @@ -2324,13 +2327,16 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { sp foregroundWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); - if (foregroundWindowHandle && foregroundWindowHandle->getInfo()->hasWallpaper) { + if (foregroundWindowHandle && + foregroundWindowHandle->getInfo()->inputConfig.test( + WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { const std::vector>& windowHandles = getWindowHandlesLocked(displayId); for (const sp& windowHandle : windowHandles) { const WindowInfo* info = windowHandle->getInfo(); if (info->displayId == displayId && - windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) { + windowHandle->getInfo()->inputConfig.test( + WindowInfo::InputConfig::IS_WALLPAPER)) { tempTouchState .addOrUpdateWindow(windowHandle, InputTarget::FLAG_WINDOW_IS_OBSCURED | @@ -2599,9 +2605,10 @@ static bool canBeObscuredBy(const sp& windowHandle, } auto info = windowHandle->getInfo(); auto otherInfo = otherHandle->getInfo(); - if (!otherInfo->visible) { + if (otherInfo->inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) { return false; - } else if (otherInfo->alpha == 0 && otherInfo->flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) { + } else if (otherInfo->alpha == 0 && + otherInfo->inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE)) { // Those act as if they were invisible, so we don't need to flag them. // We do want to potentially flag touchable windows even if they have 0 // opacity, since they can consume touches and alter the effects of the @@ -2613,7 +2620,7 @@ static bool canBeObscuredBy(const sp& windowHandle, // If ownerUid is the same we don't generate occlusion events as there // is no security boundary within an uid. return false; - } else if (otherInfo->trustedOverlay) { + } else if (otherInfo->inputConfig.test(gui::WindowInfo::InputConfig::TRUSTED_OVERLAY)) { return false; } else if (otherInfo->displayId != info->displayId) { return false; @@ -2694,17 +2701,17 @@ InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLo std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info, bool isTouchedWindow) const { return StringPrintf(INDENT2 - "* %stype=%s, package=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, " + "* %spackage=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, " "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32 - "], touchableRegion=%s, window={%s}, flags={%s}, inputFeatures={%s}, " + "], touchableRegion=%s, window={%s}, inputConfig={%s}, inputFeatures={%s}, " "hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n", - isTouchedWindow ? "[TOUCHED] " : "", ftl::enum_string(info->type).c_str(), - info->packageName.c_str(), info->ownerUid, info->id, - toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft, - info->frameTop, info->frameRight, info->frameBottom, - dumpRegion(info->touchableRegion).c_str(), info->name.c_str(), - info->flags.string().c_str(), info->inputFeatures.string().c_str(), - toString(info->token != nullptr), info->applicationInfo.name.c_str(), + isTouchedWindow ? "[TOUCHED] " : "", info->packageName.c_str(), + info->ownerUid, info->id, toString(info->touchOcclusionMode).c_str(), + info->alpha, info->frameLeft, info->frameTop, info->frameRight, + info->frameBottom, dumpRegion(info->touchableRegion).c_str(), + info->name.c_str(), info->inputConfig.string().c_str(), + info->inputFeatures.string().c_str(), toString(info->token != nullptr), + info->applicationInfo.name.c_str(), toString(info->applicationInfo.token).c_str()); } @@ -4572,8 +4579,9 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( if (getInputChannelLocked(handle->getToken()) == nullptr) { const bool noInputChannel = info->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); - const bool canReceiveInput = !info->flags.test(WindowInfo::Flag::NOT_TOUCHABLE) || - !info->flags.test(WindowInfo::Flag::NOT_FOCUSABLE); + const bool canReceiveInput = + !info->inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) || + !info->inputConfig.test(WindowInfo::InputConfig::NOT_FOCUSABLE); if (canReceiveInput && !noInputChannel) { ALOGV("Window handle %s has no registered input channel", handle->getName().c_str()); @@ -4644,12 +4652,16 @@ void InputDispatcher::setInputWindowsLocked( } // Ensure all spy windows are trusted overlays - LOG_ALWAYS_FATAL_IF(info.isSpy() && !info.trustedOverlay, + LOG_ALWAYS_FATAL_IF(info.isSpy() && + !info.inputConfig.test( + WindowInfo::InputConfig::TRUSTED_OVERLAY), "%s has feature SPY, but is not a trusted overlay.", window->getName().c_str()); // Ensure all stylus interceptors are trusted overlays - LOG_ALWAYS_FATAL_IF(info.interceptsStylus() && !info.trustedOverlay, + LOG_ALWAYS_FATAL_IF(info.interceptsStylus() && + !info.inputConfig.test( + WindowInfo::InputConfig::TRUSTED_OVERLAY), "%s has feature INTERCEPTS_STYLUS, but is not a trusted overlay.", window->getName().c_str()); } @@ -4699,7 +4711,8 @@ void InputDispatcher::setInputWindowsLocked( // Since we are about to drop the touch, cancel the events for the wallpaper as // well. if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND && - touchedWindow.windowHandle->getInfo()->hasWallpaper) { + touchedWindow.windowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { sp wallpaper = state.getWallpaperWindow(); if (wallpaper != nullptr) { sp wallpaperConnection = @@ -5194,34 +5207,27 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { const WindowInfo* windowInfo = windowHandle->getInfo(); dump += StringPrintf(INDENT3 "%zu: name='%s', id=%" PRId32 ", displayId=%d, " - "paused=%s, focusable=%s, " - "hasWallpaper=%s, visible=%s, alpha=%.2f, " - "flags=%s, type=%s, " + "inputConfig=%s, alpha=%.2f, " "frame=[%d,%d][%d,%d], globalScale=%f, " "applicationInfo.name=%s, " "applicationInfo.token=%s, " "touchableRegion=", i, windowInfo->name.c_str(), windowInfo->id, - windowInfo->displayId, toString(windowInfo->paused), - toString(windowInfo->focusable), - toString(windowInfo->hasWallpaper), - toString(windowInfo->visible), windowInfo->alpha, - windowInfo->flags.string().c_str(), - ftl::enum_string(windowInfo->type).c_str(), - windowInfo->frameLeft, windowInfo->frameTop, - windowInfo->frameRight, windowInfo->frameBottom, - windowInfo->globalScaleFactor, + windowInfo->displayId, + windowInfo->inputConfig.string().c_str(), + windowInfo->alpha, windowInfo->frameLeft, + windowInfo->frameTop, windowInfo->frameRight, + windowInfo->frameBottom, windowInfo->globalScaleFactor, windowInfo->applicationInfo.name.c_str(), toString(windowInfo->applicationInfo.token).c_str()); dump += dumpRegion(windowInfo->touchableRegion); dump += StringPrintf(", inputFeatures=%s", windowInfo->inputFeatures.string().c_str()); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64 - "ms, trustedOverlay=%s, hasToken=%s, " + "ms, hasToken=%s, " "touchOcclusionMode=%s\n", windowInfo->ownerPid, windowInfo->ownerUid, millis(windowInfo->dispatchingTimeout), - toString(windowInfo->trustedOverlay), toString(windowInfo->token != nullptr), toString(windowInfo->touchOcclusionMode).c_str()); windowInfo->transform.dump(dump, "transform", INDENT4); diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index b63fe104fa..61e78ccbe4 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -100,7 +100,8 @@ bool TouchState::isSlippery() const { for (const TouchedWindow& window : windows) { if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { if (haveSlipperyForegroundWindow || - !window.windowHandle->getInfo()->flags.test(WindowInfo::Flag::SLIPPERY)) { + !window.windowHandle->getInfo()->inputConfig.test( + WindowInfo::InputConfig::SLIPPERY)) { return false; } haveSlipperyForegroundWindow = true; @@ -112,7 +113,8 @@ bool TouchState::isSlippery() const { sp TouchState::getWallpaperWindow() const { for (size_t i = 0; i < windows.size(); i++) { const TouchedWindow& window = windows[i]; - if (window.windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) { + if (window.windowHandle->getInfo()->inputConfig.test( + gui::WindowInfo::InputConfig::IS_WALLPAPER)) { return window.windowHandle; } } diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp index 662be8063e..ffce9f68cc 100644 --- a/services/inputflinger/tests/FocusResolver_test.cpp +++ b/services/inputflinger/tests/FocusResolver_test.cpp @@ -37,12 +37,16 @@ public: bool visible) { mInfo.token = token; mInfo.name = name; - mInfo.visible = visible; - mInfo.focusable = focusable; + setFocusable(focusable); + setVisible(visible); } - void setFocusable(bool focusable) { mInfo.focusable = focusable; } - void setVisible(bool visible) { mInfo.visible = visible; } + void setFocusable(bool focusable) { + mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable); + } + void setVisible(bool visible) { + mInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible); + } }; TEST(FocusResolverTest, SetFocusedWindow) { diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 872882e5d8..8b95f28738 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -986,7 +986,6 @@ public: mInfo.token = *token; mInfo.id = sId++; mInfo.name = name; - mInfo.type = WindowInfo::Type::APPLICATION; mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; mInfo.alpha = 1.0; mInfo.frameLeft = 0; @@ -997,14 +996,14 @@ public: mInfo.globalScaleFactor = 1.0; mInfo.touchableRegion.clear(); mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT)); - mInfo.visible = true; - mInfo.focusable = false; - mInfo.hasWallpaper = false; - mInfo.paused = false; mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = displayId; - mInfo.trustedOverlay = false; + setVisible(true); + setFocusable(false); + setDupTouchToWallpaper(false); + setPaused(false); + setTrustedOverlay(false); } sp clone( @@ -1016,15 +1015,41 @@ public: return handle; } - void setFocusable(bool focusable) { mInfo.focusable = focusable; } + void setTouchable(bool touchable) { + mInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, !touchable); + } - void setVisible(bool visible) { mInfo.visible = visible; } + void setFocusable(bool focusable) { + mInfo.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable); + } + + void setVisible(bool visible) { + mInfo.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible); + } void setDispatchingTimeout(std::chrono::nanoseconds timeout) { mInfo.dispatchingTimeout = timeout; } - void setPaused(bool paused) { mInfo.paused = paused; } + void setPaused(bool paused) { + mInfo.setInputConfig(WindowInfo::InputConfig::PAUSE_DISPATCHING, paused); + } + + void setTouchModal(bool touchModal) { + mInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCH_MODAL, !touchModal); + } + + void setSplitTouch(bool splitTouch) { + mInfo.setInputConfig(WindowInfo::InputConfig::SPLIT_TOUCH, splitTouch); + } + + void setSlippery(bool slippery) { + mInfo.setInputConfig(WindowInfo::InputConfig::SLIPPERY, slippery); + } + + void setWatchOutsideTouch(bool watchOutside) { + mInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, watchOutside); + } void setAlpha(float alpha) { mInfo.alpha = alpha; } @@ -1048,17 +1073,19 @@ public: void setTouchableRegion(const Region& region) { mInfo.touchableRegion = region; } - void setType(WindowInfo::Type type) { mInfo.type = type; } - - void setHasWallpaper(bool hasWallpaper) { mInfo.hasWallpaper = hasWallpaper; } - - void addFlags(Flags flags) { mInfo.flags |= flags; } + void setIsWallpaper(bool isWallpaper) { + mInfo.setInputConfig(WindowInfo::InputConfig::IS_WALLPAPER, isWallpaper); + } - void setFlags(Flags flags) { mInfo.flags = flags; } + void setDupTouchToWallpaper(bool hasWallpaper) { + mInfo.setInputConfig(WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER, hasWallpaper); + } void setInputFeatures(Flags features) { mInfo.inputFeatures = features; } - void setTrustedOverlay(bool trustedOverlay) { mInfo.trustedOverlay = trustedOverlay; } + void setTrustedOverlay(bool trustedOverlay) { + mInfo.setInputConfig(WindowInfo::InputConfig::TRUSTED_OVERLAY, trustedOverlay); + } void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) { mInfo.transform.set(dsdx, dtdx, dtdy, dsdy); @@ -1551,7 +1578,7 @@ TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) { sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + window->setTouchModal(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1574,7 +1601,7 @@ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + window->setTouchModal(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -1609,17 +1636,17 @@ TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) { * Two windows: A top window, and a wallpaper behind the window. * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window * gets ACTION_CANCEL. - * 1. foregroundWindow <-- has wallpaper (hasWallpaper=true) - * 2. wallpaperWindow <-- is wallpaper (type=InputWindowInfo::Type::WALLPAPER) + * 1. foregroundWindow <-- dup touch to wallpaper + * 2. wallpaperWindow <-- is wallpaper */ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) { std::shared_ptr application = std::make_shared(); sp foregroundWindow = new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); - foregroundWindow->setHasWallpaper(true); + foregroundWindow->setDupTouchToWallpaper(true); sp wallpaperWindow = new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); - wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; @@ -1660,10 +1687,10 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { std::shared_ptr application = std::make_shared(); sp foregroundWindow = new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); - foregroundWindow->setHasWallpaper(true); + foregroundWindow->setDupTouchToWallpaper(true); sp wallpaperWindow = new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); - wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; @@ -1704,11 +1731,11 @@ TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); - window->setHasWallpaper(true); + window->setDupTouchToWallpaper(true); sp wallpaperWindow = new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); - wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; @@ -1762,19 +1789,21 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { sp leftWindow = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); leftWindow->setFrame(Rect(0, 0, 200, 200)); - leftWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL); - leftWindow->setHasWallpaper(true); + leftWindow->setTouchModal(false); + leftWindow->setSplitTouch(true); + leftWindow->setDupTouchToWallpaper(true); sp rightWindow = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); rightWindow->setFrame(Rect(200, 0, 400, 200)); - rightWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL); - rightWindow->setHasWallpaper(true); + rightWindow->setTouchModal(false); + rightWindow->setSplitTouch(true); + rightWindow->setDupTouchToWallpaper(true); sp wallpaperWindow = new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setFrame(Rect(0, 0, 400, 200)); - wallpaperWindow->setType(WindowInfo::Type::WALLPAPER); + wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; @@ -1848,11 +1877,11 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { sp windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + windowLeft->setTouchModal(false); sp windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + windowRight->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -1959,7 +1988,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { sp window = new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 1200, 800)); - window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + window->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -2041,11 +2070,11 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { sp windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + windowLeft->setTouchModal(false); sp windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + windowRight->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -2151,14 +2180,14 @@ public: // Add two windows to the display. Their frames are represented in the display space. sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); - firstWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + firstWindow->setTouchModal(false); firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform); addWindow(firstWindow); sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); - secondWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + secondWindow->setTouchModal(false); secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform); addWindow(secondWindow); return {std::move(firstWindow), std::move(secondWindow)}; @@ -2379,13 +2408,15 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + firstWindow->setTouchModal(false); + firstWindow->setSplitTouch(true); // Create a non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + secondWindow->setTouchModal(false); + secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2451,13 +2482,15 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + firstWindow->setTouchModal(false); + firstWindow->setSplitTouch(true); // Create a non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + secondWindow->setTouchModal(false); + secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2522,26 +2555,26 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { sp firstWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + firstWindowInPrimary->setTouchModal(false); sp secondWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + secondWindowInPrimary->setTouchModal(false); sp mirrorWindowInPrimary = firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); - mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mirrorWindowInPrimary->setTouchModal(false); sp firstWindowInSecondary = firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + firstWindowInSecondary->setTouchModal(false); sp secondWindowInSecondary = secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + secondWindowInPrimary->setTouchModal(false); // Update window info, let it find window handle of second display first. mDispatcher->setInputWindows( @@ -2586,26 +2619,26 @@ TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { sp firstWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + firstWindowInPrimary->setTouchModal(false); sp secondWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + secondWindowInPrimary->setTouchModal(false); sp mirrorWindowInPrimary = firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); - mirrorWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mirrorWindowInPrimary->setTouchModal(false); sp firstWindowInSecondary = firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInSecondary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + firstWindowInSecondary->setTouchModal(false); sp secondWindowInSecondary = secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + secondWindowInPrimary->setTouchModal(false); // Update window info, let it find window handle of second display first. mDispatcher->setInputWindows( @@ -2703,13 +2736,15 @@ TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) { sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + firstWindow->setTouchModal(false); + firstWindow->setSplitTouch(true); // Create second non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + secondWindow->setTouchModal(false); + secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -3376,7 +3411,8 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { sp slipperyExitWindow = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); - slipperyExitWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SLIPPERY); + slipperyExitWindow->setTouchModal(false); + slipperyExitWindow->setSlippery(true); // Make sure this one overlaps the bottom window slipperyExitWindow->setFrame(Rect(25, 25, 75, 75)); // Change the owner uid/pid of the window so that it is considered to be occluding the bottom @@ -3984,12 +4020,12 @@ class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. - mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mUnfocusedWindow->setTouchModal(false); mFocusedWindow = new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mFocusedWindow->setTouchModal(false); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -4098,12 +4134,14 @@ class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest { ADISPLAY_ID_DEFAULT); // Adding FLAG_NOT_TOUCH_MODAL otherwise all taps will go to the top most window. // We also need FLAG_SPLIT_TOUCH or we won't be able to get touches for both windows. - mWindow1->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + mWindow1->setTouchModal(false); + mWindow1->setSplitTouch(true); mWindow1->setFrame(Rect(0, 0, 100, 100)); mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2", ADISPLAY_ID_DEFAULT, mWindow1->getToken()); - mWindow2->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + mWindow2->setTouchModal(false); + mWindow2->setSplitTouch(true); mWindow2->setFrame(Rect(100, 100, 200, 200)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}}); @@ -4302,7 +4340,7 @@ class InputDispatcherSingleWindowAnr : public InputDispatcherTest { mWindow->setFocusable(true); // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. - mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mWindow->setTouchModal(false); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -4753,15 +4791,16 @@ class InputDispatcherMultiWindowAnr : public InputDispatcherTest { // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this // window. // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped - mUnfocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | - WindowInfo::Flag::WATCH_OUTSIDE_TOUCH | - WindowInfo::Flag::SPLIT_TOUCH); + mUnfocusedWindow->setTouchModal(false); + mUnfocusedWindow->setSplitTouch(true); + mUnfocusedWindow->setWatchOutsideTouch(true); mFocusedWindow = new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT); mFocusedWindow->setDispatchingTimeout(30ms); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + mFocusedWindow->setTouchModal(false); + mFocusedWindow->setSplitTouch(true); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -5495,7 +5534,7 @@ protected: sp getOccludingWindow(int32_t uid, std::string name, TouchOcclusionMode mode, float alpha = 1.0f) { sp window = getWindow(uid, name); - window->setFlags(WindowInfo::Flag::NOT_TOUCHABLE); + window->setTouchable(false); window->setTouchOcclusionMode(mode); window->setAlpha(alpha); return window; @@ -5609,7 +5648,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacityAndWatchOutside_ReceivesOutsideEvent) { const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); - w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH); + w->setWatchOutsideTouch(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); touch(); @@ -5620,7 +5659,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) { const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); - w->addFlags(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH); + w->setWatchOutsideTouch(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); touch(); @@ -5870,11 +5909,11 @@ protected: mApp = std::make_shared(); mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); mWindow->setFrame(Rect(0, 0, 100, 100)); - mWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mWindow->setTouchModal(false); mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); mSecondWindow->setFrame(Rect(100, 0, 200, 100)); - mSecondWindow->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL); + mSecondWindow->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}}); @@ -6129,7 +6168,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { ADISPLAY_ID_DEFAULT); obscuringWindow->setFrame(Rect(0, 0, 50, 50)); obscuringWindow->setOwnerInfo(111, 111); - obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE); + obscuringWindow->setTouchable(false); std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); @@ -6175,7 +6214,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) { ADISPLAY_ID_DEFAULT); obscuringWindow->setFrame(Rect(0, 0, 50, 50)); obscuringWindow->setOwnerInfo(111, 111); - obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE); + obscuringWindow->setTouchable(false); std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); @@ -6257,7 +6296,7 @@ TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTou class InputDispatcherSpyWindowTest : public InputDispatcherTest { public: - sp createSpy(const Flags flags) { + sp createSpy() { std::shared_ptr application = std::make_shared(); std::string name = "Fake Spy "; @@ -6266,7 +6305,7 @@ public: new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT); spy->setInputFeatures(WindowInfo::Feature::SPY); spy->setTrustedOverlay(true); - spy->addFlags(flags); + spy->setTouchModal(false); return spy; } @@ -6275,8 +6314,9 @@ public: std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - window->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); window->setFocusable(true); + window->setTouchModal(false); + window->setSplitTouch(true); return window; } @@ -6291,7 +6331,7 @@ using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest; TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) { ScopedSilentDeath _silentDeath; - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy = createSpy(); spy->setTrustedOverlay(false); ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}), ".* not a trusted overlay"); @@ -6301,7 +6341,7 @@ TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) { * Input injection into a display with a spy window but no foreground windows should succeed. */ TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) { - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy = createSpy(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -6324,9 +6364,9 @@ TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) { */ TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) { auto window = createForeground(); - auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); - auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); - auto spy3 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy1 = createSpy(); + auto spy2 = createSpy(); + auto spy3 = createSpy(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window, spy3}}}); const std::vector> channels{spy1, spy2, window, spy3}; const size_t numChannels = channels.size(); @@ -6377,7 +6417,8 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) { */ TEST_F(InputDispatcherSpyWindowTest, NotTouchable) { auto window = createForeground(); - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCHABLE); + auto spy = createSpy(); + spy->setTouchable(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -6394,7 +6435,7 @@ TEST_F(InputDispatcherSpyWindowTest, NotTouchable) { */ TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) { auto window = createForeground(); - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy = createSpy(); spy->setTouchableRegion(Region{{0, 0, 20, 20}}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6425,8 +6466,10 @@ TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) { */ TEST_F(InputDispatcherSpyWindowTest, ModalWindow) { auto window = createForeground(); - auto spy = createSpy(static_cast(0)); - // This spy window does not have the NOT_TOUCH_MODAL flag set. + auto spy = createSpy(); + // Our current policy dictates that modal windows must be focusable. + spy->setFocusable(true); + spy->setTouchModal(true); spy->setFrame(Rect{0, 0, 20, 20}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6445,7 +6488,9 @@ TEST_F(InputDispatcherSpyWindowTest, ModalWindow) { TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { auto window = createForeground(); window->setOwnerInfo(12, 34); - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::WATCH_OUTSIDE_TOUCH); + auto spy = createSpy(); + spy->setWatchOutsideTouch(true); + spy->setTouchModal(false); spy->setOwnerInfo(56, 78); spy->setFrame(Rect{0, 0, 20, 20}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6465,8 +6510,8 @@ TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { */ TEST_F(InputDispatcherSpyWindowTest, PilferPointers) { auto window = createForeground(); - auto spy1 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); - auto spy2 = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy1 = createSpy(); + auto spy2 = createSpy(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -6498,7 +6543,7 @@ TEST_F(InputDispatcherSpyWindowTest, PilferPointers) { */ TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) { auto window = createForeground(); - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy = createSpy(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -6522,9 +6567,9 @@ TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) { * the spy, but not to any other windows. */ TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) { - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); + auto spy = createSpy(); + spy->setTouchModal(false); auto window = createForeground(); - window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6590,7 +6635,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { windowLeft->setFrame({0, 0, 100, 200}); auto windowRight = createForeground(); windowRight->setFrame({100, 0, 200, 200}); - auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spy = createSpy(); spy->setFrame({0, 0, 200, 200}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, windowLeft, windowRight}}}); @@ -6625,7 +6670,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { auto window = createForeground(); window->setFrame({0, 0, 200, 200}); - auto spyRight = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL); + auto spyRight = createSpy(); spyRight->setFrame({100, 0, 200, 200}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyRight, window}}}); @@ -6659,14 +6704,15 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { */ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { // Create a touch modal spy that spies on the entire display. - // This spy window does not set the SPLIT_TOUCH flag. However, we still expect to split touches + // This spy window does not set split touch. However, we still expect to split touches // because a foreground window has not disabled splitting. - auto spy = createSpy(static_cast(0)); + auto spy = createSpy(); + spy->setTouchModal(true); + spy->setSplitTouch(false); // Create a non touch modal window that supports split touch. auto window = createForeground(); window->setFrame(Rect(0, 0, 100, 100)); - window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6704,7 +6750,7 @@ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { * do not receive key events. */ TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) { - auto spy = createSpy(static_cast(0)); + auto spy = createSpy(); spy->setFocusable(false); auto window = createForeground(); @@ -6733,7 +6779,8 @@ public: ADISPLAY_ID_DEFAULT); overlay->setFocusable(false); overlay->setOwnerInfo(111, 111); - overlay->setFlags(WindowInfo::Flag::NOT_TOUCHABLE | WindowInfo::Flag::SPLIT_TOUCH); + overlay->setTouchable(false); + overlay->setSplitTouch(true); overlay->setInputFeatures(WindowInfo::Feature::INTERCEPTS_STYLUS); overlay->setTrustedOverlay(true); @@ -6744,7 +6791,7 @@ public: ADISPLAY_ID_DEFAULT); window->setFocusable(true); window->setOwnerInfo(222, 222); - window->setFlags(WindowInfo::Flag::SPLIT_TOUCH); + window->setSplitTouch(true); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index a039250327..d290a76e2f 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2161,8 +2161,8 @@ Rect Layer::getInputBounds() const { void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) { Rect tmpBounds = getInputBounds(); if (!tmpBounds.isValid()) { - info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE; - info.focusable = false; + info.inputConfig |= + WindowInfo::InputConfig::NOT_TOUCH_MODAL | WindowInfo::InputConfig::NOT_FOCUSABLE; info.touchableRegion.clear(); // A layer could have invalid input bounds and still expect to receive touch input if it has // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated @@ -2309,7 +2309,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp mDrawingState.inputInfo.ownerUid = mOwnerUid; mDrawingState.inputInfo.ownerPid = mOwnerPid; mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL; - mDrawingState.inputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL; + mDrawingState.inputInfo.inputConfig |= WindowInfo::InputConfig::NOT_TOUCH_MODAL; mDrawingState.inputInfo.displayId = getLayerStack().id; } @@ -2327,7 +2327,9 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp // We are just using these layers for occlusion detection in // InputDispatcher, and obviously if they aren't visible they can't occlude // anything. - info.visible = hasInputInfo() ? canReceiveInput() : isVisible(); + const bool visible = hasInputInfo() ? canReceiveInput() : isVisible(); + info.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible); + info.alpha = getAlpha(); fillTouchOcclusionMode(info); handleDropInputMode(info); @@ -2349,8 +2351,9 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state // if it was set by WM for a known system overlay - info.trustedOverlay = info.trustedOverlay || isTrustedOverlay(); - + if (isTrustedOverlay()) { + info.inputConfig |= WindowInfo::InputConfig::TRUSTED_OVERLAY; + } // If the layer is a clone, we need to crop the input region to cloned root to prevent // touches from going outside the cloned area. @@ -2482,7 +2485,7 @@ void Layer::updateClonedInputInfo(const std::map, sp>& clonedLa } // Cloned layers shouldn't handle watch outside since their z order is not determined by // WM or the client. - mDrawingState.inputInfo.flags &= ~WindowInfo::Flag::WATCH_OUTSIDE_TOUCH; + mDrawingState.inputInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, false); } void Layer::updateClonedRelatives(const std::map, sp>& clonedLayersMap) { diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index 015caa6a9b..bc06b5cfe8 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -175,12 +175,12 @@ void LayerProtoHelper::writeToProto( } InputWindowInfoProto* proto = getInputWindowInfoProto(); - proto->set_layout_params_flags(inputInfo.flags.get()); + proto->set_layout_params_flags(inputInfo.layoutParamsFlags.get()); using U = std::underlying_type_t; // TODO(b/129481165): This static assert can be safely removed once conversion warnings // are re-enabled. static_assert(std::is_same_v); - proto->set_layout_params_type(static_cast(inputInfo.type)); + proto->set_layout_params_type(static_cast(inputInfo.layoutParamsType)); LayerProtoHelper::writeToProto({inputInfo.frameLeft, inputInfo.frameTop, inputInfo.frameRight, inputInfo.frameBottom}, @@ -189,9 +189,10 @@ void LayerProtoHelper::writeToProto( [&]() { return proto->mutable_touchable_region(); }); proto->set_surface_inset(inputInfo.surfaceInset); - proto->set_visible(inputInfo.visible); - proto->set_focusable(inputInfo.focusable); - proto->set_has_wallpaper(inputInfo.hasWallpaper); + using InputConfig = gui::WindowInfo::InputConfig; + proto->set_visible(!inputInfo.inputConfig.test(InputConfig::NOT_VISIBLE)); + proto->set_focusable(!inputInfo.inputConfig.test(InputConfig::NOT_FOCUSABLE)); + proto->set_has_wallpaper(inputInfo.inputConfig.test(InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)); proto->set_global_scale_factor(inputInfo.globalScaleFactor); LayerProtoHelper::writeToProtoDeprecated(inputInfo.transform, proto->mutable_transform()); diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index a91698fb79..c736d05506 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -183,13 +183,16 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer, if (layer.windowInfoHandle) { const gui::WindowInfo* inputInfo = layer.windowInfoHandle->getInfo(); proto::LayerState_WindowInfo* windowInfoProto = proto.mutable_window_info_handle(); - windowInfoProto->set_layout_params_flags(inputInfo->flags.get()); - windowInfoProto->set_layout_params_type(static_cast(inputInfo->type)); + windowInfoProto->set_layout_params_flags(inputInfo->layoutParamsFlags.get()); + windowInfoProto->set_layout_params_type( + static_cast(inputInfo->layoutParamsType)); LayerProtoHelper::writeToProto(inputInfo->touchableRegion, windowInfoProto->mutable_touchable_region()); windowInfoProto->set_surface_inset(inputInfo->surfaceInset); - windowInfoProto->set_focusable(inputInfo->focusable); - windowInfoProto->set_has_wallpaper(inputInfo->hasWallpaper); + windowInfoProto->set_focusable( + !inputInfo->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE)); + windowInfoProto->set_has_wallpaper(inputInfo->inputConfig.test( + gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)); windowInfoProto->set_global_scale_factor(inputInfo->globalScaleFactor); proto::LayerState_Transform* transformProto = windowInfoProto->mutable_transform(); transformProto->set_dsdx(inputInfo->transform.dsdx()); @@ -471,13 +474,17 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, gui::WindowInfo inputInfo; const proto::LayerState_WindowInfo& windowInfoProto = proto.window_info_handle(); - inputInfo.flags = static_cast(windowInfoProto.layout_params_flags()); - inputInfo.type = static_cast(windowInfoProto.layout_params_type()); + inputInfo.layoutParamsFlags = + static_cast(windowInfoProto.layout_params_flags()); + inputInfo.layoutParamsType = + static_cast(windowInfoProto.layout_params_type()); LayerProtoHelper::readFromProto(windowInfoProto.touchable_region(), inputInfo.touchableRegion); inputInfo.surfaceInset = windowInfoProto.surface_inset(); - inputInfo.focusable = windowInfoProto.focusable(); - inputInfo.hasWallpaper = windowInfoProto.has_wallpaper(); + inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_FOCUSABLE, + !windowInfoProto.focusable()); + inputInfo.setInputConfig(gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER, + windowInfoProto.has_wallpaper()); inputInfo.globalScaleFactor = windowInfoProto.global_scale_factor(); const proto::LayerState_Transform& transformProto = windowInfoProto.transform(); inputInfo.transform.set(transformProto.dsdx(), transformProto.dtdx(), transformProto.dtdy(), -- cgit v1.2.3-59-g8ed1b From d8f5e9fedc217ca9c257599b2c624b260b6852d6 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 3 Feb 2022 10:23:28 -0800 Subject: SF: Save proto traces to a specific path Test: presubmit Bug: 200284593 Change-Id: I6987329cc32b2ca13e76e957a5ae6b17bbed6e83 --- services/surfaceflinger/Layer.cpp | 18 ++++++++---------- services/surfaceflinger/Layer.h | 4 ++-- services/surfaceflinger/LayerProtoHelper.cpp | 12 ++++++------ services/surfaceflinger/SurfaceFlinger.cpp | 22 +++++++++------------- services/surfaceflinger/SurfaceFlinger.h | 5 +++++ services/surfaceflinger/Tracing/LayerTracing.cpp | 4 ++-- services/surfaceflinger/Tracing/LayerTracing.h | 2 +- services/surfaceflinger/Tracing/RingBuffer.h | 2 +- .../surfaceflinger/Tracing/TransactionTracing.cpp | 4 ++-- .../surfaceflinger/Tracing/TransactionTracing.h | 2 +- 10 files changed, 37 insertions(+), 38 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index a039250327..973029cb19 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1993,29 +1993,31 @@ void Layer::setInputInfo(const WindowInfo& info) { setTransactionFlags(eTransactionNeeded); } -LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags, - const DisplayDevice* display) { +LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags) { LayerProto* layerProto = layersProto.add_layers(); - writeToProtoDrawingState(layerProto, traceFlags, display); + writeToProtoDrawingState(layerProto); writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags); if (traceFlags & LayerTracing::TRACE_COMPOSITION) { // Only populate for the primary display. + UnnecessaryLock assumeLocked(mFlinger->mStateLock); // called from the main thread. + const auto display = mFlinger->getDefaultDisplayDeviceLocked(); if (display) { const auto compositionType = getCompositionType(*display); layerProto->set_hwc_composition_type(static_cast(compositionType)); + LayerProtoHelper::writeToProto(getVisibleRegion(display.get()), + [&]() { return layerProto->mutable_visible_region(); }); } } for (const sp& layer : mDrawingChildren) { - layer->writeToProto(layersProto, traceFlags, display); + layer->writeToProto(layersProto, traceFlags); } return layerProto; } -void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, - const DisplayDevice* display) { +void Layer::writeToProtoDrawingState(LayerProto* layerInfo) { const ui::Transform transform = getTransform(); auto buffer = getExternalTexture(); if (buffer != nullptr) { @@ -2039,10 +2041,6 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(), [&]() { return layerInfo->mutable_position(); }); LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); }); - if (traceFlags & LayerTracing::TRACE_COMPOSITION) { - LayerProtoHelper::writeToProto(getVisibleRegion(display), - [&]() { return layerInfo->mutable_visible_region(); }); - } LayerProtoHelper::writeToProto(surfaceDamageRegion, [&]() { return layerInfo->mutable_damage_region(); }); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index e51af1e10e..21dd5f4954 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -686,12 +686,12 @@ public: bool isRemovedFromCurrentState() const; - LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags, const DisplayDevice*); + LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags); // Write states that are modified by the main thread. This includes drawing // state as well as buffer data. This should be called in the main or tracing // thread. - void writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags, const DisplayDevice*); + void writeToProtoDrawingState(LayerProto* layerInfo); // Write drawing or current state. If writing current state, the caller should hold the // external mStateLock. If writing drawing state, this function should be called on the // main or tracing thread. diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index 015caa6a9b..3bd0643a6d 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -156,14 +156,14 @@ void LayerProtoHelper::writeTransformToProto(const ui::Transform& transform, void LayerProtoHelper::writeToProto(const renderengine::ExternalTexture& buffer, std::function getActiveBufferProto) { - if (buffer.getBuffer()->getWidth() != 0 || buffer.getBuffer()->getHeight() != 0 || - buffer.getBuffer()->getUsage() != 0 || buffer.getBuffer()->getPixelFormat() != 0) { + if (buffer.getWidth() != 0 || buffer.getHeight() != 0 || buffer.getUsage() != 0 || + buffer.getPixelFormat() != 0) { // Use a lambda do avoid writing the object header when the object is empty ActiveBufferProto* activeBufferProto = getActiveBufferProto(); - activeBufferProto->set_width(buffer.getBuffer()->getWidth()); - activeBufferProto->set_height(buffer.getBuffer()->getHeight()); - activeBufferProto->set_format(buffer.getBuffer()->getPixelFormat()); - activeBufferProto->set_usage(buffer.getBuffer()->getUsage()); + activeBufferProto->set_width(buffer.getWidth()); + activeBufferProto->set_height(buffer.getHeight()); + activeBufferProto->set_stride(buffer.getUsage()); + activeBufferProto->set_format(buffer.getPixelFormat()); } } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 980d1dca54..5991b86d5d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -250,11 +250,6 @@ struct SCOPED_CAPABILITY TimedLock { const status_t status; }; -struct SCOPED_CAPABILITY UnnecessaryLock { - explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {} - ~UnnecessaryLock() RELEASE() {} -}; - // TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity. constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV; @@ -5102,11 +5097,9 @@ void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { } LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); - LayersProto layersProto; for (const sp& layer : mDrawingState.layersSortedByZ) { - layer->writeToProto(layersProto, traceFlags, display.get()); + layer->writeToProto(layersProto, traceFlags); } return layersProto; @@ -5147,8 +5140,7 @@ void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t rootProto->add_children(offscreenLayer->sequence); // Add layer - LayerProto* layerProto = - offscreenLayer->writeToProto(layersProto, traceFlags, nullptr /*device*/); + LayerProto* layerProto = offscreenLayer->writeToProto(layersProto, traceFlags); layerProto->set_parent(offscreenRootLayerId); } } @@ -5743,9 +5735,9 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } case 1025: { // Set layer tracing n = data.readInt32(); - int64_t fixedStartingTime = data.readInt64(); bool tracingEnabledChanged; - if (n) { + if (n == 1) { + int64_t fixedStartingTime = data.readInt64(); ALOGD("LayerTracing enabled"); tracingEnabledChanged = mLayerTracing.enable(); if (tracingEnabledChanged) { @@ -5757,6 +5749,10 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r }) .wait(); } + } else if (n == 2) { + std::string filename = std::string(data.readCString()); + ALOGD("LayerTracing disabled. Trace wrote to %s", filename.c_str()); + tracingEnabledChanged = mLayerTracing.disable(filename.c_str()); } else { ALOGD("LayerTracing disabled"); tracingEnabledChanged = mLayerTracing.disable(); @@ -6009,9 +6005,9 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r mTransactionTracing->setBufferSize( TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE); } else { + mTransactionTracing->writeToFile(); mTransactionTracing->setBufferSize( TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE); - mTransactionTracing->writeToFile(); } } reply->writeInt32(NO_ERROR); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 95255738c6..02d5f1e49e 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -177,6 +177,11 @@ struct SurfaceFlingerBE { std::atomic mLastSwapTime = 0; }; +struct SCOPED_CAPABILITY UnnecessaryLock { + explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {} + ~UnnecessaryLock() RELEASE() {} +}; + class SurfaceFlinger : public BnSurfaceComposer, public PriorityDumper, private IBinder::DeathRecipient, diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp index 006efdfd61..49554c7dd8 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.cpp +++ b/services/surfaceflinger/Tracing/LayerTracing.cpp @@ -45,14 +45,14 @@ bool LayerTracing::enable() { return true; } -bool LayerTracing::disable() { +bool LayerTracing::disable(std::string filename) { std::scoped_lock lock(mTraceLock); if (!mEnabled) { return false; } mEnabled = false; LayersTraceFileProto fileProto = createTraceFileProto(); - mBuffer->writeToFile(fileProto, FILE_NAME); + mBuffer->writeToFile(fileProto, filename); mBuffer->reset(); return true; } diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h index bd448c956d..88a19ecdf1 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.h +++ b/services/surfaceflinger/Tracing/LayerTracing.h @@ -43,7 +43,7 @@ public: LayerTracing(SurfaceFlinger& flinger); ~LayerTracing(); bool enable(); - bool disable(); + bool disable(std::string filename = FILE_NAME); bool isEnabled() const; status_t writeToFile(); LayersTraceFileProto createTraceFileProto() const; diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h index 3b2626d489..7e38c55840 100644 --- a/services/surfaceflinger/Tracing/RingBuffer.h +++ b/services/surfaceflinger/Tracing/RingBuffer.h @@ -67,7 +67,7 @@ public: // -rw-r--r-- const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; if (!android::base::WriteStringToFile(output, filename, mode, getuid(), getgid(), true)) { - ALOGE("Could not save the proto file."); + ALOGE("Could not save the proto file %s", filename.c_str()); return PERMISSION_DENIED; } return NO_ERROR; diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp index 298e63ab67..d5e837f879 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.cpp +++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp @@ -99,11 +99,11 @@ TransactionTracing::~TransactionTracing() { writeToFile(); } -status_t TransactionTracing::writeToFile() { +status_t TransactionTracing::writeToFile(std::string filename) { std::scoped_lock lock(mTraceLock); proto::TransactionTraceFile fileProto = createTraceFileProto(); addStartingStateToProtoLocked(fileProto); - return mBuffer.writeToFile(fileProto, FILE_NAME); + return mBuffer.writeToFile(fileProto, filename); } void TransactionTracing::setBufferSize(size_t bufferSizeInBytes) { diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h index c20f22a94b..95256c4047 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.h +++ b/services/surfaceflinger/Tracing/TransactionTracing.h @@ -55,7 +55,7 @@ public: void addQueuedTransaction(const TransactionState&); void addCommittedTransactions(std::vector& transactions, int64_t vsyncId); - status_t writeToFile(); + status_t writeToFile(std::string filename = FILE_NAME); void setBufferSize(size_t bufferSizeInBytes); void onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, uint32_t flags, int parentId); -- cgit v1.2.3-59-g8ed1b From 76bdecb09d6a124838edf8495ce90ef4dc0cc3c8 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 31 Jan 2022 11:14:15 -0800 Subject: Invert some InputConfig flags to simplify default behavior Invert NOT_TOUCH_MODAL to TOUCH_MODAL, and SPLIT_TOUCH to PREVENT_SPLITTING. Modal windows and windows that prevent splitting are exceptional behaviors, so we make sure that these show up when outputting flag values using ftl::Flags::string(). Bug: 216806304 Test: atest inputflinger_tests Change-Id: I7cadcc830f06ff0c63da3b61a1a7580cb031f0c2 --- libs/gui/WindowInfo.cpp | 2 +- libs/gui/include/gui/WindowInfo.h | 4 +- libs/gui/tests/EndToEndNativeInputTest.cpp | 3 - .../inputflinger/dispatcher/InputDispatcher.cpp | 5 +- .../inputflinger/tests/InputDispatcher_test.cpp | 105 +++------------------ services/surfaceflinger/Layer.cpp | 6 +- 6 files changed, 20 insertions(+), 105 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 2c25e7e2ac..80bd6389a0 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -47,7 +47,7 @@ bool WindowInfo::frameContainsPoint(int32_t x, int32_t y) const { } bool WindowInfo::supportsSplitTouch() const { - return inputConfig.test(InputConfig::SPLIT_TOUCH); + return !inputConfig.test(InputConfig::PREVENT_SPLITTING); } bool WindowInfo::isSpy() const { diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 1b3419a25b..c8d49865f0 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -164,8 +164,8 @@ struct WindowInfo : public Parcelable { NOT_VISIBLE = 1 << 0, NOT_FOCUSABLE = 1 << 1, NOT_TOUCHABLE = 1 << 2, - NOT_TOUCH_MODAL = 1 << 3, - SPLIT_TOUCH = 1 << 4, + TOUCH_MODAL = 1 << 3, + PREVENT_SPLITTING = 1 << 4, DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 5, IS_WALLPAPER = 1 << 6, PAUSE_DISPATCHING = 1 << 7, diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 1151aa3f0f..fcfe21bee2 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -268,9 +268,6 @@ private: mInputInfo.name = "Test info"; mInputInfo.dispatchingTimeout = 5s; mInputInfo.globalScaleFactor = 1.0; - mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCH_MODAL, true); - mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, false); - mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height)); InputApplicationInfo aInfo; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index a26256318a..f5aa45b66c 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -509,9 +509,8 @@ bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32 if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) { return false; } - const bool isModalWindow = !inputConfig.test(WindowInfo::InputConfig::NOT_FOCUSABLE) && - !inputConfig.test(WindowInfo::InputConfig::NOT_TOUCH_MODAL); - if (!isModalWindow && !windowInfo.touchableRegionContainsPoint(x, y)) { + if (!inputConfig.test(WindowInfo::InputConfig::TOUCH_MODAL) && + !windowInfo.touchableRegionContainsPoint(x, y)) { return false; } return true; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index da65e176e5..51ecf763a1 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1000,11 +1000,7 @@ public: mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = displayId; - setVisible(true); - setFocusable(false); - setDupTouchToWallpaper(false); - setPaused(false); - setTrustedOverlay(false); + mInfo.inputConfig = WindowInfo::InputConfig::NONE; } sp clone( @@ -1037,11 +1033,11 @@ public: } void setTouchModal(bool touchModal) { - mInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCH_MODAL, !touchModal); + mInfo.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, touchModal); } - void setSplitTouch(bool splitTouch) { - mInfo.setInputConfig(WindowInfo::InputConfig::SPLIT_TOUCH, splitTouch); + void setPreventSplitting(bool preventSplitting) { + mInfo.setInputConfig(WindowInfo::InputConfig::PREVENT_SPLITTING, preventSplitting); } void setSlippery(bool slippery) { @@ -1567,19 +1563,15 @@ TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay } /** - * Calling setInputWindows once with FLAG_NOT_TOUCH_MODAL should not cause any issues. - * To ensure that window receives only events that were directly inside of it, add - * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input - * when finding touched windows. + * Calling setInputWindows once should not cause any issues. * This test serves as a sanity check for the next test, where setInputWindows is * called twice. */ -TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) { +TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setTouchModal(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1593,16 +1585,12 @@ TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) { /** * Calling setInputWindows twice, with the same info, should not cause any issues. - * To ensure that window receives only events that were directly inside of it, add - * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input - * when finding touched windows. */ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setTouchModal(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -1790,15 +1778,11 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { sp leftWindow = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); leftWindow->setFrame(Rect(0, 0, 200, 200)); - leftWindow->setTouchModal(false); - leftWindow->setSplitTouch(true); leftWindow->setDupTouchToWallpaper(true); sp rightWindow = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); rightWindow->setFrame(Rect(200, 0, 400, 200)); - rightWindow->setTouchModal(false); - rightWindow->setSplitTouch(true); rightWindow->setDupTouchToWallpaper(true); sp wallpaperWindow = @@ -1878,11 +1862,9 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { sp windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setTouchModal(false); sp windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -1989,7 +1971,6 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { sp window = new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 1200, 800)); - window->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -2071,11 +2052,9 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { sp windowLeft = new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); windowLeft->setFrame(Rect(0, 0, 600, 800)); - windowLeft->setTouchModal(false); sp windowRight = new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); windowRight->setFrame(Rect(600, 0, 1200, 800)); - windowRight->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -2181,14 +2160,12 @@ public: // Add two windows to the display. Their frames are represented in the display space. sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); - firstWindow->setTouchModal(false); firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform); addWindow(firstWindow); sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); - secondWindow->setTouchModal(false); secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform); addWindow(secondWindow); return {std::move(firstWindow), std::move(secondWindow)}; @@ -2331,8 +2308,10 @@ TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { // Create a couple of windows sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); + firstWindow->setPreventSplitting(true); sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); + secondWindow->setPreventSplitting(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2405,19 +2384,13 @@ INSTANTIATE_TEST_SUITE_P(TransferFunctionTests, TransferTouchFixture, TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { std::shared_ptr application = std::make_shared(); - // Create a non touch modal window that supports split touch sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setTouchModal(false); - firstWindow->setSplitTouch(true); - // Create a non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setTouchModal(false); - secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2479,19 +2452,13 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { std::shared_ptr application = std::make_shared(); - // Create a non touch modal window that supports split touch sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setTouchModal(false); - firstWindow->setSplitTouch(true); - // Create a non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setTouchModal(false); - secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -2556,26 +2523,21 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { sp firstWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInPrimary->setTouchModal(false); sp secondWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setTouchModal(false); sp mirrorWindowInPrimary = firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); - mirrorWindowInPrimary->setTouchModal(false); sp firstWindowInSecondary = firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInSecondary->setTouchModal(false); sp secondWindowInSecondary = secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setTouchModal(false); // Update window info, let it find window handle of second display first. mDispatcher->setInputWindows( @@ -2620,26 +2582,21 @@ TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { sp firstWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT); firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInPrimary->setTouchModal(false); sp secondWindowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setTouchModal(false); sp mirrorWindowInPrimary = firstWindowInPrimary->clone(application, mDispatcher, ADISPLAY_ID_DEFAULT); mirrorWindowInPrimary->setFrame(Rect(0, 100, 100, 200)); - mirrorWindowInPrimary->setTouchModal(false); sp firstWindowInSecondary = firstWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); firstWindowInSecondary->setFrame(Rect(0, 0, 100, 100)); - firstWindowInSecondary->setTouchModal(false); sp secondWindowInSecondary = secondWindowInPrimary->clone(application, mDispatcher, SECOND_DISPLAY_ID); secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); - secondWindowInPrimary->setTouchModal(false); // Update window info, let it find window handle of second display first. mDispatcher->setInputWindows( @@ -2733,19 +2690,13 @@ TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) { TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) { std::shared_ptr application = std::make_shared(); - // Create first non touch modal window that supports split touch sp firstWindow = new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT); firstWindow->setFrame(Rect(0, 0, 600, 400)); - firstWindow->setTouchModal(false); - firstWindow->setSplitTouch(true); - // Create second non touch modal window that supports split touch sp secondWindow = new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT); secondWindow->setFrame(Rect(0, 400, 600, 800)); - secondWindow->setTouchModal(false); - secondWindow->setSplitTouch(true); // Add the windows to the dispatcher mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); @@ -3265,9 +3216,9 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); + window->setFocusable(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - // Window is not focusable. mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); setFocusedWindow(window); @@ -3275,7 +3226,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) { ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; - // window is invalid, so it should not receive any input event. + // window is not focusable, so it should not receive any input event. window->assertNoEvents(); } @@ -3412,7 +3363,6 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { sp slipperyExitWindow = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); - slipperyExitWindow->setTouchModal(false); slipperyExitWindow->setSlippery(true); // Make sure this one overlaps the bottom window slipperyExitWindow->setFrame(Rect(25, 25, 75, 75)); @@ -4019,14 +3969,10 @@ class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { mUnfocusedWindow = new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); - // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this - // window. - mUnfocusedWindow->setTouchModal(false); mFocusedWindow = new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setTouchModal(false); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -4133,16 +4079,10 @@ class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest { std::make_shared(); mWindow1 = new FakeWindowHandle(application, mDispatcher, "Fake Window 1", ADISPLAY_ID_DEFAULT); - // Adding FLAG_NOT_TOUCH_MODAL otherwise all taps will go to the top most window. - // We also need FLAG_SPLIT_TOUCH or we won't be able to get touches for both windows. - mWindow1->setTouchModal(false); - mWindow1->setSplitTouch(true); mWindow1->setFrame(Rect(0, 0, 100, 100)); mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2", ADISPLAY_ID_DEFAULT, mWindow1->getToken()); - mWindow2->setTouchModal(false); - mWindow2->setSplitTouch(true); mWindow2->setFrame(Rect(100, 100, 200, 200)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}}); @@ -4339,9 +4279,6 @@ class InputDispatcherSingleWindowAnr : public InputDispatcherTest { mWindow->setFrame(Rect(0, 0, 30, 30)); mWindow->setDispatchingTimeout(30ms); mWindow->setFocusable(true); - // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this - // window. - mWindow->setTouchModal(false); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -4789,19 +4726,13 @@ class InputDispatcherMultiWindowAnr : public InputDispatcherTest { mUnfocusedWindow = new FakeWindowHandle(mApplication, mDispatcher, "Unfocused", ADISPLAY_ID_DEFAULT); mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); - // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this - // window. // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped - mUnfocusedWindow->setTouchModal(false); - mUnfocusedWindow->setSplitTouch(true); mUnfocusedWindow->setWatchOutsideTouch(true); mFocusedWindow = new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT); mFocusedWindow->setDispatchingTimeout(30ms); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); - mFocusedWindow->setTouchModal(false); - mFocusedWindow->setSplitTouch(true); // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); @@ -5910,11 +5841,9 @@ protected: mApp = std::make_shared(); mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); mWindow->setFrame(Rect(0, 0, 100, 100)); - mWindow->setTouchModal(false); mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); mSecondWindow->setFrame(Rect(100, 0, 200, 100)); - mSecondWindow->setTouchModal(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}}); @@ -6330,7 +6259,6 @@ public: new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT); spy->setInputFeatures(WindowInfo::Feature::SPY); spy->setTrustedOverlay(true); - spy->setTouchModal(false); return spy; } @@ -6340,8 +6268,6 @@ public: sp window = new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); - window->setTouchModal(false); - window->setSplitTouch(true); return window; } @@ -6515,7 +6441,6 @@ TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { window->setOwnerInfo(12, 34); auto spy = createSpy(); spy->setWatchOutsideTouch(true); - spy->setTouchModal(false); spy->setOwnerInfo(56, 78); spy->setFrame(Rect{0, 0, 20, 20}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6593,7 +6518,6 @@ TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) { */ TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) { auto spy = createSpy(); - spy->setTouchModal(false); auto window = createForeground(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6728,14 +6652,11 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { * windows should be allowed to control split touch. */ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { - // Create a touch modal spy that spies on the entire display. - // This spy window does not set split touch. However, we still expect to split touches + // This spy window prevents touch splitting. However, we still expect to split touches // because a foreground window has not disabled splitting. auto spy = createSpy(); - spy->setTouchModal(true); - spy->setSplitTouch(false); + spy->setPreventSplitting(true); - // Create a non touch modal window that supports split touch. auto window = createForeground(); window->setFrame(Rect(0, 0, 100, 100)); @@ -6805,7 +6726,6 @@ public: overlay->setFocusable(false); overlay->setOwnerInfo(111, 111); overlay->setTouchable(false); - overlay->setSplitTouch(true); overlay->setInputFeatures(WindowInfo::Feature::INTERCEPTS_STYLUS); overlay->setTrustedOverlay(true); @@ -6816,7 +6736,6 @@ public: ADISPLAY_ID_DEFAULT); window->setFocusable(true); window->setOwnerInfo(222, 222); - window->setSplitTouch(true); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d0d79e9dd3..219c7164c1 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2159,8 +2159,8 @@ Rect Layer::getInputBounds() const { void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) { Rect tmpBounds = getInputBounds(); if (!tmpBounds.isValid()) { - info.inputConfig |= - WindowInfo::InputConfig::NOT_TOUCH_MODAL | WindowInfo::InputConfig::NOT_FOCUSABLE; + info.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, false); + info.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, true); info.touchableRegion.clear(); // A layer could have invalid input bounds and still expect to receive touch input if it has // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated @@ -2307,7 +2307,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp mDrawingState.inputInfo.ownerUid = mOwnerUid; mDrawingState.inputInfo.ownerPid = mOwnerPid; mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL; - mDrawingState.inputInfo.inputConfig |= WindowInfo::InputConfig::NOT_TOUCH_MODAL; + mDrawingState.inputInfo.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, false); mDrawingState.inputInfo.displayId = getLayerStack().id; } -- cgit v1.2.3-59-g8ed1b From 06349040a46db18701ddff7cdd87da22ee7ba27c Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 4 Feb 2022 09:19:17 -0800 Subject: Remove the concept of TOUCH_MODAL from input We remove modal windows from input. WM will configure modal windows itself using touchableRegion. Bug: 216806304 Test: atest inputflinger_tests Change-Id: I9593865213216b420ab9b5c5b853298f01dabcc6 --- libs/gui/include/gui/WindowInfo.h | 15 ++++++------- .../inputflinger/dispatcher/InputDispatcher.cpp | 3 +-- .../inputflinger/tests/InputDispatcher_test.cpp | 25 ---------------------- services/surfaceflinger/Layer.cpp | 2 -- 4 files changed, 8 insertions(+), 37 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index c8d49865f0..b9bffaa6a0 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -164,18 +164,17 @@ struct WindowInfo : public Parcelable { NOT_VISIBLE = 1 << 0, NOT_FOCUSABLE = 1 << 1, NOT_TOUCHABLE = 1 << 2, - TOUCH_MODAL = 1 << 3, - PREVENT_SPLITTING = 1 << 4, - DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 5, - IS_WALLPAPER = 1 << 6, - PAUSE_DISPATCHING = 1 << 7, + PREVENT_SPLITTING = 1 << 3, + DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 4, + IS_WALLPAPER = 1 << 5, + PAUSE_DISPATCHING = 1 << 6, // This flag is set when the window is of a trusted type that is allowed to silently // overlay other windows for the purpose of implementing the secure views feature. // Trusted overlays, such as IME windows, can partly obscure other windows without causing // motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - TRUSTED_OVERLAY = 1 << 8, - WATCH_OUTSIDE_TOUCH = 1 << 9, - SLIPPERY = 1 << 10, + TRUSTED_OVERLAY = 1 << 7, + WATCH_OUTSIDE_TOUCH = 1 << 8, + SLIPPERY = 1 << 9, // clang-format on }; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index f5aa45b66c..58c93036bb 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -509,8 +509,7 @@ bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32 if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) { return false; } - if (!inputConfig.test(WindowInfo::InputConfig::TOUCH_MODAL) && - !windowInfo.touchableRegionContainsPoint(x, y)) { + if (!windowInfo.touchableRegionContainsPoint(x, y)) { return false; } return true; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 51ecf763a1..ae8358aa5d 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1032,10 +1032,6 @@ public: mInfo.setInputConfig(WindowInfo::InputConfig::PAUSE_DISPATCHING, paused); } - void setTouchModal(bool touchModal) { - mInfo.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, touchModal); - } - void setPreventSplitting(bool preventSplitting) { mInfo.setInputConfig(WindowInfo::InputConfig::PREVENT_SPLITTING, preventSplitting); } @@ -6411,27 +6407,6 @@ TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) { spy->consumeMotionDown(); } -/** - * A spy window that is a modal window will receive gestures outside of its frame and touchable - * region. - */ -TEST_F(InputDispatcherSpyWindowTest, ModalWindow) { - auto window = createForeground(); - auto spy = createSpy(); - // Our current policy dictates that modal windows must be focusable. - spy->setFocusable(true); - spy->setTouchModal(true); - spy->setFrame(Rect{0, 0, 20, 20}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); - - // Inject an event outside the spy window's frame and touchable region. - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) - << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionDown(); - spy->consumeMotionDown(); -} - /** * A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES * flag, but it will get zero-ed out coordinates if the foreground has a different owner. diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 219c7164c1..808109603f 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2159,7 +2159,6 @@ Rect Layer::getInputBounds() const { void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) { Rect tmpBounds = getInputBounds(); if (!tmpBounds.isValid()) { - info.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, false); info.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, true); info.touchableRegion.clear(); // A layer could have invalid input bounds and still expect to receive touch input if it has @@ -2307,7 +2306,6 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp mDrawingState.inputInfo.ownerUid = mOwnerUid; mDrawingState.inputInfo.ownerPid = mOwnerPid; mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL; - mDrawingState.inputInfo.setInputConfig(WindowInfo::InputConfig::TOUCH_MODAL, false); mDrawingState.inputInfo.displayId = getLayerStack().id; } -- cgit v1.2.3-59-g8ed1b From d2aaab14d2fd52a6c6a0c928a55bf000f6c538ca Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 10 Feb 2022 14:49:09 -0800 Subject: SurfaceView: Avoid destination frame updates on multiple threads 2/2 The caller such as SurfaceView can optionally apply destination frame changes if they wish to synchronize buffer scale with other scales in the hierarchy. This is hard to synchronize if the buffer scale changes, since in fixed scaling mode we want the destination frame to be applied when a buffer of the new size is queued. This approach is brittle because SurfaceView does not have control over the buffer production and the app can get into a scenario where there is scaled incorrectly. Fix this by configuring BBQ to always apply destination frame changes or always defer to the caller. If the scaling mode is freeze, then BBQ will set a flag to ignore the destination frame. This allows us to synchronize destination frame changes with scale applied by a parent and avoid unwanted scaling if the scaling mode changes to freeze. Test: atest SurfaceViewTest Test: go/wm-smoke Bug: 217973491 Change-Id: I0d214e3f7e45c38e6222a2947ca354c36a202ff5 --- libs/gui/BLASTBufferQueue.cpp | 35 +++++++++++++------------ libs/gui/include/gui/BLASTBufferQueue.h | 16 +++++------ libs/gui/include/gui/LayerState.h | 9 +++++-- services/surfaceflinger/BufferStateLayer.cpp | 3 ++- services/surfaceflinger/Layer.cpp | 3 +++ services/surfaceflinger/layerproto/layers.proto | 2 ++ 6 files changed, 40 insertions(+), 28 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 7ce72ffa59..b7a7aa0ccb 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -132,12 +132,13 @@ void BLASTBufferItemConsumer::onSidebandStreamChanged() { } } -BLASTBufferQueue::BLASTBufferQueue(const std::string& name) +BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinationFrame) : mSurfaceControl(nullptr), mSize(1, 1), mRequestedSize(mSize), mFormat(PIXEL_FORMAT_RGBA_8888), - mSyncTransaction(nullptr) { + mSyncTransaction(nullptr), + mUpdateDestinationFrame(updateDestinationFrame) { createBufferQueue(&mProducer, &mConsumer); // since the adapter is in the client process, set dequeue timeout // explicitly so that dequeueBuffer will block @@ -184,7 +185,7 @@ BLASTBufferQueue::~BLASTBufferQueue() { } void BLASTBufferQueue::update(const sp& surface, uint32_t width, uint32_t height, - int32_t format, SurfaceComposerClient::Transaction* outTransaction) { + int32_t format) { LOG_ALWAYS_FATAL_IF(surface == nullptr, "BLASTBufferQueue: mSurfaceControl must not be NULL"); std::unique_lock _lock{mMutex}; @@ -193,7 +194,6 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format)); } - SurfaceComposerClient::Transaction t; const bool surfaceControlChanged = !SurfaceControl::isSameSurface(mSurfaceControl, surface); if (surfaceControlChanged && mSurfaceControl != nullptr) { BQA_LOGD("Updating SurfaceControl without recreating BBQ"); @@ -203,6 +203,7 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, // Always update the native object even though they might have the same layer handle, so we can // get the updated transform hint from WM. mSurfaceControl = surface; + SurfaceComposerClient::Transaction t; if (surfaceControlChanged) { t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, layer_state_t::eEnableBackpressure); @@ -221,12 +222,10 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, // If the buffer supports scaling, update the frame immediately since the client may // want to scale the existing buffer to the new size. mSize = mRequestedSize; - SurfaceComposerClient::Transaction* destFrameTransaction = - (outTransaction) ? outTransaction : &t; - destFrameTransaction->setDestinationFrame(mSurfaceControl, - Rect(0, 0, newSize.getWidth(), - newSize.getHeight())); - applyTransaction = true; + if (mUpdateDestinationFrame) { + t.setDestinationFrame(mSurfaceControl, Rect(newSize)); + applyTransaction = true; + } } } if (applyTransaction) { @@ -498,7 +497,6 @@ void BLASTBufferQueue::acquireNextBufferLocked( // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. incStrong((void*)transactionCallbackThunk); - const bool updateDestinationFrame = mRequestedSize != mSize; mSize = mRequestedSize; Rect crop = computeCrop(bufferItem); mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(), @@ -517,12 +515,19 @@ void BLASTBufferQueue::acquireNextBufferLocked( mSurfaceControlsWithPendingCallback.push(mSurfaceControl); - if (updateDestinationFrame) { - t->setDestinationFrame(mSurfaceControl, Rect(0, 0, mSize.getWidth(), mSize.getHeight())); + if (mUpdateDestinationFrame) { + t->setDestinationFrame(mSurfaceControl, Rect(mSize)); + } else { + const bool ignoreDestinationFrame = + bufferItem.mScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE; + t->setFlags(mSurfaceControl, + ignoreDestinationFrame ? layer_state_t::eIgnoreDestinationFrame : 0, + layer_state_t::eIgnoreDestinationFrame); } t->setBufferCrop(mSurfaceControl, crop); t->setTransform(mSurfaceControl, bufferItem.mTransform); t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse); + t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh); if (!bufferItem.mIsAutoTimestamp) { t->setDesiredPresentTime(bufferItem.mTimestamp); } @@ -532,10 +537,6 @@ void BLASTBufferQueue::acquireNextBufferLocked( mNextFrameTimelineInfoQueue.pop(); } - if (mAutoRefresh != bufferItem.mAutoRefresh) { - t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh); - mAutoRefresh = bufferItem.mAutoRefresh; - } { std::unique_lock _lock{mTimestampMutex}; auto dequeueTime = mDequeueTimestamps.find(buffer->getId()); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 1ed592b506..74addeac4a 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -73,7 +73,7 @@ class BLASTBufferQueue : public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener { public: - BLASTBufferQueue(const std::string& name); + BLASTBufferQueue(const std::string& name, bool updateDestinationFrame = true); BLASTBufferQueue(const std::string& name, const sp& surface, int width, int height, int32_t format); @@ -100,8 +100,7 @@ public: void applyPendingTransactions(uint64_t frameNumber); SurfaceComposerClient::Transaction* gatherPendingTransactions(uint64_t frameNumber); - void update(const sp& surface, uint32_t width, uint32_t height, int32_t format, - SurfaceComposerClient::Transaction* outTransaction = nullptr); + void update(const sp& surface, uint32_t width, uint32_t height, int32_t format); status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); status_t setFrameTimelineInfo(const FrameTimelineInfo& info); @@ -218,11 +217,6 @@ private: std::vector> mPendingTransactions GUARDED_BY(mMutex); - // Last requested auto refresh state set by the producer. The state 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 for shared buffer mode. - bool mAutoRefresh GUARDED_BY(mMutex) = false; - std::queue mNextFrameTimelineInfoQueue GUARDED_BY(mMutex); // Tracks the last acquired frame number @@ -250,6 +244,12 @@ private: // Flag to determine if syncTransaction should only acquire a single buffer and then clear or // continue to acquire buffers until explicitly cleared bool mAcquireSingleBuffer GUARDED_BY(mMutex) = true; + + // True if BBQ will update the destination frame used to scale the buffer to the requested size. + // If false, the caller is responsible for updating the destination frame on the BBQ + // surfacecontol. This is useful if the caller wants to synchronize the buffer scale with + // additional scales in the hierarchy. + bool mUpdateDestinationFrame GUARDED_BY(mMutex) = true; }; } // namespace android diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index f7206193cd..ac9e428c9d 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -128,8 +128,13 @@ struct layer_state_t { // Queue up BufferStateLayer buffers instead of dropping the oldest buffer when this flag is // set. This blocks the client until all the buffers have been presented. If the buffers // have presentation timestamps, then we may drop buffers. - eEnableBackpressure = 0x100, // ENABLE_BACKPRESSURE - eLayerIsDisplayDecoration = 0x200, // DISPLAY_DECORATION + eEnableBackpressure = 0x100, // ENABLE_BACKPRESSURE + eLayerIsDisplayDecoration = 0x200, // DISPLAY_DECORATION + // Ignore any destination frame set on the layer. This is used when the buffer scaling mode + // is freeze and the destination frame is applied asynchronously with the buffer submission. + // This is needed to maintain compatibility for SurfaceView scaling behavior. + // See SurfaceView scaling behavior for more details. + eIgnoreDestinationFrame = 0x400, }; enum { diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 02e444df8e..e6a76e8ea9 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -271,7 +271,8 @@ static bool assignTransform(ui::Transform* dst, ui::Transform& from) { // Translate destination frame into scale and position. If a destination frame is not set, use the // provided scale and position bool BufferStateLayer::updateGeometry() { - if (mDrawingState.destinationFrame.isEmpty()) { + if ((mDrawingState.flags & layer_state_t::eIgnoreDestinationFrame) || + mDrawingState.destinationFrame.isEmpty()) { // If destination frame is not set, use the requested transform set via // BufferStateLayer::setPosition and BufferStateLayer::setMatrix. return assignTransform(&mDrawingState.transform, mRequestedTransform); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 808109603f..533acfdefe 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2142,6 +2142,9 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend()); } } + + LayerProtoHelper::writeToProto(state.destinationFrame, + [&]() { return layerInfo->mutable_destination_frame(); }); } bool Layer::isRemovedFromCurrentState() const { diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto index 2e9e659880..3598308338 100644 --- a/services/surfaceflinger/layerproto/layers.proto +++ b/services/surfaceflinger/layerproto/layers.proto @@ -136,6 +136,8 @@ message LayerProto { // Corner radius explicitly set on layer rather than inherited float requested_corner_radius = 56; + + RectProto destination_frame = 57; } message PositionProto { -- cgit v1.2.3-59-g8ed1b From 2c1782c6f986debe5ec89d5cdd3a3f08b08d5683 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Wed, 16 Feb 2022 15:25:05 -0800 Subject: Hide layers that have irreversible transforms Surface API doesn't prohibit putting interesting values in transforms. It's especially possible to scale something to 0 at the begining or the end of an animation, but we should guard SF against ill-intentioned apps. Bug: 210837722 Test: KeyguardTests#testDismissKeyguardActivity doesn't crash SF on CF PC and the warning log is in logcat. Change-Id: Idaa1cdb0676102a580c4478c860327796c8213f3 --- libs/ui/Transform.cpp | 6 +++++- libs/ui/include/ui/Transform.h | 1 + services/surfaceflinger/Layer.cpp | 15 +++++++++++++++ services/surfaceflinger/Layer.h | 1 + 4 files changed, 22 insertions(+), 1 deletion(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp index b34d90699f..42dd85e959 100644 --- a/libs/ui/Transform.cpp +++ b/libs/ui/Transform.cpp @@ -134,6 +134,10 @@ float Transform::dsdy() const { return mMatrix[1][1]; } +float Transform::det() const { + return mMatrix[0][0] * mMatrix[1][1] - mMatrix[0][1] * mMatrix[1][0]; +} + float Transform::getScaleX() const { return sqrt((dsdx() * dsdx()) + (dtdx() * dtdx())); } @@ -390,7 +394,7 @@ Transform Transform::inverse() const { const float x = M[2][0]; const float y = M[2][1]; - const float idet = 1.0f / (a*d - b*c); + const float idet = 1.0f / det(); result.mMatrix[0][0] = d*idet; result.mMatrix[0][1] = -c*idet; result.mMatrix[1][0] = -b*idet; diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h index 33fbe05035..f1178cab35 100644 --- a/libs/ui/include/ui/Transform.h +++ b/libs/ui/include/ui/Transform.h @@ -77,6 +77,7 @@ public: float dtdx() const; float dtdy() const; float dsdy() const; + float det() const; float getScaleX() const; float getScaleY() const; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 533acfdefe..4de8dc2ea9 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -338,6 +338,12 @@ void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform, // Calculate effective layer transform mEffectiveTransform = parentTransform * getActiveTransform(s); + if (CC_UNLIKELY(!isTransformValid())) { + ALOGW("Stop computing bounds for %s because it has invalid transformation.", + getDebugName()); + return; + } + // Transform parent bounds to layer space parentBounds = getActiveTransform(s).inverse().transform(parentBounds); @@ -1326,6 +1332,10 @@ bool Layer::isHiddenByPolicy() const { } } } + if (CC_UNLIKELY(!isTransformValid())) { + ALOGW("Hide layer %s because it has invalid transformation.", getDebugName()); + return true; + } return s.flags & layer_state_t::eLayerHidden; } @@ -1858,6 +1868,11 @@ ui::Transform Layer::getTransform() const { return mEffectiveTransform; } +bool Layer::isTransformValid() const { + float transformDet = getTransform().det(); + return transformDet != 0 && !isinf(transformDet) && !isnan(transformDet); +} + half Layer::getAlpha() const { const auto& p = mDrawingParent.promote(); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 21dd5f4954..2b5e337095 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -752,6 +752,7 @@ public: FrameEventHistoryDelta* outDelta); ui::Transform getTransform() const; + bool isTransformValid() const; // Returns the Alpha of the Surface, accounting for the Alpha // of parent Surfaces in the hierarchy (alpha's will be multiplied -- cgit v1.2.3-59-g8ed1b From 51e7db07902f5dc7b19f8b45cfc0f2b66764cdda Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 7 Feb 2022 06:02:57 -0800 Subject: WindowInfo: Merge InputConfig and Feature flags Merge the two flags in native code. We move the InputConfig flag defintions to AIDL since we will be using the flags in Java as part of the InputWindowHandle API next. InputFeatureFlags are now a WM-only flag, but is temporarily used by InputWindowHandle until the cleanup is completed. Bug: 216806304 Test: atest libgui_test Test: atest inputflinger_tests Change-Id: I82d6de35b30d9cd4bcaf61499216c8faf407e885 --- libs/gui/WindowInfo.cpp | 10 +- libs/gui/include/gui/WindowInfo.h | 69 +++++----- libs/gui/tests/WindowInfo_test.cpp | 2 - libs/input/Android.bp | 7 +- libs/input/android/os/IInputConstants.aidl | 49 ------- libs/input/android/os/InputConfig.aidl | 147 +++++++++++++++++++++ .../inputflinger/dispatcher/InputDispatcher.cpp | 33 +++-- .../inputflinger/tests/InputDispatcher_test.cpp | 46 ++++--- services/surfaceflinger/Layer.cpp | 16 +-- 9 files changed, 239 insertions(+), 140 deletions(-) create mode 100644 libs/input/android/os/InputConfig.aidl (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 80bd6389a0..b02bae49d3 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -51,11 +51,11 @@ bool WindowInfo::supportsSplitTouch() const { } bool WindowInfo::isSpy() const { - return inputFeatures.test(Feature::SPY); + return inputConfig.test(InputConfig::SPY); } bool WindowInfo::interceptsStylus() const { - return inputFeatures.test(Feature::INTERCEPTS_STYLUS); + return inputConfig.test(InputConfig::INTERCEPTS_STYLUS); } bool WindowInfo::overlaps(const WindowInfo* other) const { @@ -73,8 +73,7 @@ bool WindowInfo::operator==(const WindowInfo& info) const { info.touchableRegion.hasSameRects(touchableRegion) && info.touchOcclusionMode == touchOcclusionMode && info.ownerPid == ownerPid && info.ownerUid == ownerUid && info.packageName == packageName && - info.inputFeatures == inputFeatures && info.inputConfig == inputConfig && - info.displayId == displayId && + info.inputConfig == inputConfig && info.displayId == displayId && info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType && info.layoutParamsFlags == layoutParamsFlags; @@ -92,7 +91,6 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeInt32(1); // Ensure that the size of the flags that we use is 32 bits for writing into the parcel. - static_assert(sizeof(inputFeatures) == 4u); static_assert(sizeof(inputConfig) == 4u); // clang-format off @@ -120,7 +118,6 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeInt32(ownerPid) ?: parcel->writeInt32(ownerUid) ?: parcel->writeUtf8AsUtf16(packageName) ?: - parcel->writeInt32(inputFeatures.get()) ?: parcel->writeInt32(inputConfig.get()) ?: parcel->writeInt32(displayId) ?: applicationInfo.writeToParcel(parcel) ?: @@ -178,7 +175,6 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { touchOcclusionMode = static_cast(touchOcclusionModeInt); - inputFeatures = Flags(parcel->readInt32()); inputConfig = Flags(parcel->readInt32()); // clang-format off status = parcel->readInt32(&displayId) ?: diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index b9bffaa6a0..ef0b98b5cb 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -17,7 +17,7 @@ #pragma once #include -#include +#include #include #include #include @@ -132,49 +132,45 @@ struct WindowInfo : public Parcelable { ftl_last = FIRST_SYSTEM_WINDOW + 15 }; - // This is a conversion of os::IInputConstants::InputFeature to an enum backed by an unsigned + // Flags used to determine configuration of this input window. + // This is a conversion of os::InputConfig to an enum backed by an unsigned // type. This indicates that they are flags, so it can be used with ftl/enum.h. - enum class Feature : uint32_t { + enum class InputConfig : uint32_t { // clang-format off + DEFAULT = + static_cast(os::InputConfig::DEFAULT), NO_INPUT_CHANNEL = - static_cast(os::IInputConstants::InputFeature::NO_INPUT_CHANNEL), + static_cast(os::InputConfig::NO_INPUT_CHANNEL), + NOT_VISIBLE = + static_cast(os::InputConfig::NOT_VISIBLE), + NOT_FOCUSABLE = + static_cast(os::InputConfig::NOT_FOCUSABLE), + NOT_TOUCHABLE = + static_cast(os::InputConfig::NOT_TOUCHABLE), + PREVENT_SPLITTING = + static_cast(os::InputConfig::PREVENT_SPLITTING), + DUPLICATE_TOUCH_TO_WALLPAPER = + static_cast(os::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER), + IS_WALLPAPER = + static_cast(os::InputConfig::IS_WALLPAPER), + PAUSE_DISPATCHING = + static_cast(os::InputConfig::PAUSE_DISPATCHING), + TRUSTED_OVERLAY = + static_cast(os::InputConfig::TRUSTED_OVERLAY), + WATCH_OUTSIDE_TOUCH = + static_cast(os::InputConfig::WATCH_OUTSIDE_TOUCH), + SLIPPERY = + static_cast(os::InputConfig::SLIPPERY), DISABLE_USER_ACTIVITY = - static_cast(os::IInputConstants::InputFeature::DISABLE_USER_ACTIVITY), + static_cast(os::InputConfig::DISABLE_USER_ACTIVITY), DROP_INPUT = - static_cast(os::IInputConstants::InputFeature::DROP_INPUT), + static_cast(os::InputConfig::DROP_INPUT), DROP_INPUT_IF_OBSCURED = - static_cast(os::IInputConstants::InputFeature::DROP_INPUT_IF_OBSCURED), + static_cast(os::InputConfig::DROP_INPUT_IF_OBSCURED), SPY = - static_cast(os::IInputConstants::InputFeature::SPY), + static_cast(os::InputConfig::SPY), INTERCEPTS_STYLUS = - static_cast(os::IInputConstants::InputFeature::INTERCEPTS_STYLUS), - // clang-format on - }; - - // Flags used to determine configuration of this input window. - // Input windows can be configured with two sets of flags: InputFeature (WindowInfo::Feature - // defined above), and InputConfig. When adding a new configuration for an input window: - // - If you are adding a new flag that's visible and accessible to apps, it should be added - // as an InputFeature. - // - If you are adding an internal behaviour that is used within the system or shell and is - // not exposed to apps, it should be added as an InputConfig. - enum class InputConfig : uint32_t { - // clang-format off - NONE = 0, - NOT_VISIBLE = 1 << 0, - NOT_FOCUSABLE = 1 << 1, - NOT_TOUCHABLE = 1 << 2, - PREVENT_SPLITTING = 1 << 3, - DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 4, - IS_WALLPAPER = 1 << 5, - PAUSE_DISPATCHING = 1 << 6, - // This flag is set when the window is of a trusted type that is allowed to silently - // overlay other windows for the purpose of implementing the secure views feature. - // Trusted overlays, such as IME windows, can partly obscure other windows without causing - // motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - TRUSTED_OVERLAY = 1 << 7, - WATCH_OUTSIDE_TOUCH = 1 << 8, - SLIPPERY = 1 << 9, + static_cast(os::InputConfig::INTERCEPTS_STYLUS), // clang-format on }; @@ -228,7 +224,6 @@ struct WindowInfo : public Parcelable { int32_t ownerPid = -1; int32_t ownerUid = -1; std::string packageName; - Flags inputFeatures; Flags inputConfig; int32_t displayId = ADISPLAY_ID_NONE; InputApplicationInfo applicationInfo; diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index ff9bae2800..c51b244c50 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -64,7 +64,6 @@ TEST(WindowInfo, Parcelling) { i.ownerPid = 19; i.ownerUid = 24; i.packageName = "com.example.package"; - i.inputFeatures = WindowInfo::Feature::DISABLE_USER_ACTIVITY; i.inputConfig = WindowInfo::InputConfig::NOT_FOCUSABLE; i.displayId = 34; i.replaceTouchableRegionWithCrop = true; @@ -97,7 +96,6 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.ownerPid, i2.ownerPid); ASSERT_EQ(i.ownerUid, i2.ownerUid); ASSERT_EQ(i.packageName, i2.packageName); - ASSERT_EQ(i.inputFeatures, i2.inputFeatures); ASSERT_EQ(i.inputConfig, i2.inputConfig); ASSERT_EQ(i.displayId, i2.displayId); ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop); diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 930d8194d5..606fe2a59d 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -30,6 +30,7 @@ filegroup { "android/os/IInputConstants.aidl", "android/os/InputEventInjectionResult.aidl", "android/os/InputEventInjectionSync.aidl", + "android/os/InputConfig.aidl", ], } @@ -79,11 +80,8 @@ cc_library { android: { srcs: [ "InputTransport.cpp", - "android/os/BlockUntrustedTouchesMode.aidl", - "android/os/IInputConstants.aidl", "android/os/IInputFlinger.aidl", - "android/os/InputEventInjectionResult.aidl", - "android/os/InputEventInjectionSync.aidl", + ":inputconstants_aidl", ], export_shared_lib_headers: ["libbinder"], @@ -119,6 +117,7 @@ cc_library { "InputTransport.cpp", "android/os/IInputConstants.aidl", "android/os/IInputFlinger.aidl", + "android/os/InputConfig.aidl", ], static_libs: [ "libhostgraphics", diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl index 265cbf0c0b..5ce10a4a50 100644 --- a/libs/input/android/os/IInputConstants.aidl +++ b/libs/input/android/os/IInputConstants.aidl @@ -47,55 +47,6 @@ interface IInputConstants */ const int INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800; - @Backing(type="int") - enum InputFeature { - /** - * Does not construct an input channel for this window. The channel will therefore - * be incapable of receiving input. - */ - NO_INPUT_CHANNEL = 0x00000002, - - /** - * When this window has focus, does not call user activity for all input events so - * the application will have to do it itself. Should only be used by - * the keyguard and phone app. - * - * Should only be used by the keyguard and phone app. - */ - DISABLE_USER_ACTIVITY = 0x00000004, - - /** - * Internal flag used to indicate that input should be dropped on this window. - */ - DROP_INPUT = 0x00000008, - - /** - * Internal flag used to indicate that input should be dropped on this window if this window - * is obscured. - */ - DROP_INPUT_IF_OBSCURED = 0x00000010, - - /** - * An input spy window. This window will receive all pointer events within its touchable - * area, but will will not stop events from being sent to other windows below it in z-order. - * An input event will be dispatched to all spy windows above the top non-spy window at the - * event's coordinates. - */ - SPY = 0x00000020, - - /** - * When used with the window flag {@link #FLAG_NOT_TOUCHABLE}, this window will continue - * to receive events from a stylus device within its touchable region. All other pointer - * events, such as from a mouse or touchscreen, will be dispatched to the windows behind it. - * - * This input feature has no effect when the window flag {@link #FLAG_NOT_TOUCHABLE} is - * not set. - * - * The window must be a trusted overlay to use this input feature. - */ - INTERCEPTS_STYLUS = 0x00000040, - } - /* The default pointer acceleration value. */ const int DEFAULT_POINTER_ACCELERATION = 3; } diff --git a/libs/input/android/os/InputConfig.aidl b/libs/input/android/os/InputConfig.aidl new file mode 100644 index 0000000000..6d1b3967f7 --- /dev/null +++ b/libs/input/android/os/InputConfig.aidl @@ -0,0 +1,147 @@ +/** + * Copyright (c) 2022, 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. + */ + +package android.os; + + +/** + * Input configurations flags used to determine the behavior of input windows. + * @hide + */ +@Backing(type="int") +enum InputConfig { + + /** + * The default InputConfig value with no flags set. + */ + DEFAULT = 0, + + /** + * Does not construct an input channel for this window. The channel will therefore + * be incapable of receiving input. + */ + NO_INPUT_CHANNEL = 1 << 0, + + /** + * Indicates that this input window is not visible, and thus will not be considered as + * an input target and will not obscure other windows. + */ + NOT_VISIBLE = 1 << 1, + + /** + * Indicates that this input window cannot be a focus target, and this will not + * receive any input events that can only be directed for the focused window, such + * as key events. + */ + NOT_FOCUSABLE = 1 << 2, + + /** + * Indicates that this input window cannot receive any events directed at a + * specific location on the screen, such as touchscreen, mouse, and stylus events. + * The window will not be considered as a touch target, but can still obscure other + * windows. + */ + NOT_TOUCHABLE = 1 << 3, + + /** + * Indicates that this window will not accept a touch event that is split between + * more than one window. When set: + * - If this window receives a DOWN event with the first pointer, all successive + * pointers that go down, regardless of their location on the screen, will be + * directed to this window; + * - If the DOWN event lands outside the touchable bounds of this window, no + * successive pointers that go down, regardless of their location on the screen, + * will be directed to this window. + */ + PREVENT_SPLITTING = 1 << 4, + + /** + * Indicates that this window shows the wallpaper behind it, so all touch events + * that it receives should also be sent to the wallpaper. + */ + DUPLICATE_TOUCH_TO_WALLPAPER = 1 << 5, + + /** Indicates that this the wallpaper's input window. */ + IS_WALLPAPER = 1 << 6, + + /** + * Indicates that input events should not be dispatched to this window. When set, + * input events directed towards this window will simply be dropped, and will not + * be dispatched to windows behind it. + */ + PAUSE_DISPATCHING = 1 << 7, + + /** + * This flag is set when the window is of a trusted type that is allowed to silently + * overlay other windows for the purpose of implementing the secure views feature. + * Trusted overlays, such as IME windows, can partly obscure other windows without causing + * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. + */ + TRUSTED_OVERLAY = 1 << 8, + + /** + * Indicates that this window wants to listen for when there is a touch DOWN event + * that occurs outside its touchable bounds. When such an event occurs, this window + * will receive a MotionEvent with ACTION_OUTSIDE. + */ + WATCH_OUTSIDE_TOUCH = 1 << 9, + + /** + * When set, this flag allows touches to leave the current window whenever the finger + * moves above another window. When this happens, the window that touch has just left + * (the current window) will receive ACTION_CANCEL, and the window that touch has entered + * will receive ACTION_DOWN, and the remainder of the touch gesture will only go to the + * new window. Without this flag, the entire gesture is sent to the current window, even + * if the touch leaves the window's bounds. + */ + SLIPPERY = 1 << 10, + + /** + * When this window has focus, does not call user activity for all input events so + * the application will have to do it itself. + */ + DISABLE_USER_ACTIVITY = 1 << 11, + + /** + * Internal flag used to indicate that input should be dropped on this window. + */ + DROP_INPUT = 1 << 12, + + /** + * Internal flag used to indicate that input should be dropped on this window if this window + * is obscured. + */ + DROP_INPUT_IF_OBSCURED = 1 << 13, + + /** + * An input spy window. This window will receive all pointer events within its touchable + * area, but will not stop events from being sent to other windows below it in z-order. + * An input event will be dispatched to all spy windows above the top non-spy window at the + * event's coordinates. + */ + SPY = 1 << 14, + + /** + * When used with {@link #NOT_TOUCHABLE}, this window will continue to receive events from + * a stylus device within its touchable region. All other pointer events, such as from a + * mouse or touchscreen, will be dispatched to the windows behind it. + * + * This configuration has no effect when the config {@link #NOT_TOUCHABLE} is not set. + * + * It is not valid to set this configuration if {@link #TRUSTED_OVERLAY} is not set. + */ + INTERCEPTS_STYLUS = 1 << 15, +} diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 32c3a12a13..7a0022293a 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2698,18 +2698,16 @@ InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLo std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info, bool isTouchedWindow) const { - return StringPrintf(INDENT2 - "* %spackage=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, " - "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32 - "], touchableRegion=%s, window={%s}, inputConfig={%s}, inputFeatures={%s}, " - "hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n", + return StringPrintf(INDENT2 "* %spackage=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, " + "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32 + "], touchableRegion=%s, window={%s}, inputConfig={%s}, " + "hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n", isTouchedWindow ? "[TOUCHED] " : "", info->packageName.c_str(), info->ownerUid, info->id, toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft, info->frameTop, info->frameRight, info->frameBottom, dumpRegion(info->touchableRegion).c_str(), info->name.c_str(), info->inputConfig.string().c_str(), - info->inputFeatures.string().c_str(), toString(info->token != nullptr), - info->applicationInfo.name.c_str(), + toString(info->token != nullptr), info->applicationInfo.name.c_str(), toString(info->applicationInfo.token).c_str()); } @@ -2787,7 +2785,7 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { sp focusedWindowHandle = getFocusedWindowHandleLocked(displayId); if (focusedWindowHandle != nullptr) { const WindowInfo* info = focusedWindowHandle->getInfo(); - if (info->inputFeatures.test(WindowInfo::Feature::DISABLE_USER_ACTIVITY)) { + if (info->inputConfig.test(WindowInfo::InputConfig::DISABLE_USER_ACTIVITY)) { if (DEBUG_DISPATCH_CYCLE) { ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str()); } @@ -4516,7 +4514,7 @@ sp InputDispatcher::getFocusedWindowHandleLocked(int displayId bool InputDispatcher::hasResponsiveConnectionLocked(WindowInfoHandle& windowHandle) const { sp connection = getConnectionLocked(windowHandle.getToken()); const bool noInputChannel = - windowHandle.getInfo()->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); + windowHandle.getInfo()->inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL); if (connection != nullptr && noInputChannel) { ALOGW("%s has feature NO_INPUT_CHANNEL, but it matched to connection %s", windowHandle.getName().c_str(), connection->inputChannel->getName().c_str()); @@ -4566,7 +4564,7 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( const WindowInfo* info = handle->getInfo(); if (getInputChannelLocked(handle->getToken()) == nullptr) { const bool noInputChannel = - info->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); + info->inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL); const bool canReceiveInput = !info->inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) || !info->inputConfig.test(WindowInfo::InputConfig::NOT_FOCUSABLE); @@ -4632,7 +4630,7 @@ void InputDispatcher::setInputWindowsLocked( const WindowInfo& info = *window->getInfo(); // Ensure all tokens are null if the window has feature NO_INPUT_CHANNEL - const bool noInputWindow = info.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL); + const bool noInputWindow = info.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL); if (noInputWindow && window->getToken() != nullptr) { ALOGE("%s has feature NO_INPUT_WINDOW, but a non-null token. Clearing", window->getName().c_str()); @@ -5209,8 +5207,6 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { windowInfo->applicationInfo.name.c_str(), toString(windowInfo->applicationInfo.token).c_str()); dump += dumpRegion(windowInfo->touchableRegion); - dump += StringPrintf(", inputFeatures=%s", - windowInfo->inputFeatures.string().c_str()); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64 "ms, hasToken=%s, " "touchOcclusionMode=%s\n", @@ -6248,13 +6244,14 @@ void InputDispatcher::onWindowInfosChanged(const std::vector& window bool InputDispatcher::shouldDropInput( const EventEntry& entry, const sp& windowHandle) const { - if (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT) || - (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED) && + if (windowHandle->getInfo()->inputConfig.test(WindowInfo::InputConfig::DROP_INPUT) || + (windowHandle->getInfo()->inputConfig.test( + WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED) && isWindowObscuredLocked(windowHandle))) { - ALOGW("Dropping %s event targeting %s as requested by input feature %s on display " - "%" PRId32 ".", + ALOGW("Dropping %s event targeting %s as requested by the input configuration {%s} on " + "display %" PRId32 ".", ftl::enum_string(entry.type).c_str(), windowHandle->getName().c_str(), - windowHandle->getInfo()->inputFeatures.string().c_str(), + windowHandle->getInfo()->inputConfig.string().c_str(), windowHandle->getInfo()->displayId); return true; } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index b3f51ee576..b3fea74219 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -991,7 +991,7 @@ public: mInfo.ownerPid = INJECTOR_PID; mInfo.ownerUid = INJECTOR_UID; mInfo.displayId = displayId; - mInfo.inputConfig = WindowInfo::InputConfig::NONE; + mInfo.inputConfig = WindowInfo::InputConfig::DEFAULT; } sp clone( @@ -1035,6 +1035,24 @@ public: mInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, watchOutside); } + void setSpy(bool spy) { mInfo.setInputConfig(WindowInfo::InputConfig::SPY, spy); } + + void setInterceptsStylus(bool interceptsStylus) { + mInfo.setInputConfig(WindowInfo::InputConfig::INTERCEPTS_STYLUS, interceptsStylus); + } + + void setDropInput(bool dropInput) { + mInfo.setInputConfig(WindowInfo::InputConfig::DROP_INPUT, dropInput); + } + + void setDropInputIfObscured(bool dropInputIfObscured) { + mInfo.setInputConfig(WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED, dropInputIfObscured); + } + + void setNoInputChannel(bool noInputChannel) { + mInfo.setInputConfig(WindowInfo::InputConfig::NO_INPUT_CHANNEL, noInputChannel); + } + void setAlpha(float alpha) { mInfo.alpha = alpha; } void setTouchOcclusionMode(TouchOcclusionMode mode) { mInfo.touchOcclusionMode = mode; } @@ -1065,8 +1083,6 @@ public: mInfo.setInputConfig(WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER, hasWallpaper); } - void setInputFeatures(Flags features) { mInfo.inputFeatures = features; } - void setTrustedOverlay(bool trustedOverlay) { mInfo.setInputConfig(WindowInfo::InputConfig::TRUSTED_OVERLAY, trustedOverlay); } @@ -1219,7 +1235,7 @@ public: void assertNoEvents() { if (mInputReceiver == nullptr && - mInfo.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL)) { + mInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) { return; // Can't receive events if the window does not have input channel } ASSERT_NE(nullptr, mInputReceiver) @@ -4301,7 +4317,7 @@ protected: new FakeWindowHandle(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); spy->setTrustedOverlay(true); spy->setFocusable(false); - spy->setInputFeatures(WindowInfo::Feature::SPY); + spy->setSpy(true); spy->setDispatchingTimeout(30ms); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, mWindow}}}); return spy; @@ -5094,7 +5110,7 @@ class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest { "Window without input channel", ADISPLAY_ID_DEFAULT, std::make_optional>(nullptr) /*token*/); - mNoInputWindow->setInputFeatures(WindowInfo::Feature::NO_INPUT_CHANNEL); + mNoInputWindow->setNoInputChannel(true); mNoInputWindow->setFrame(Rect(0, 0, 100, 100)); // It's perfectly valid for this window to not have an associated input channel @@ -5136,7 +5152,7 @@ TEST_F(InputDispatcherMultiWindowOcclusionTests, "Window with input channel and NO_INPUT_CHANNEL", ADISPLAY_ID_DEFAULT); - mNoInputWindow->setInputFeatures(WindowInfo::Feature::NO_INPUT_CHANNEL); + mNoInputWindow->setNoInputChannel(true); mNoInputWindow->setFrame(Rect(0, 0, 100, 100)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mNoInputWindow, mBottomWindow}}}); @@ -6051,7 +6067,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); - window->setInputFeatures(WindowInfo::Feature::DROP_INPUT); + window->setDropInput(true); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -6070,7 +6086,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { window->assertNoEvents(); // With the flag cleared, the window should get input - window->setInputFeatures({}); + window->setDropInput(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); @@ -6096,7 +6112,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); - window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED); + window->setDropInputIfObscured(true); window->setOwnerInfo(222, 222); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); @@ -6116,7 +6132,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { window->assertNoEvents(); // With the flag cleared, the window should get input - window->setInputFeatures({}); + window->setDropInputIfObscured(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); @@ -6142,7 +6158,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) { std::shared_ptr application = std::make_shared(); sp window = new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); - window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED); + window->setDropInputIfObscured(true); window->setOwnerInfo(222, 222); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); @@ -6251,7 +6267,7 @@ public: name += std::to_string(mSpyCount++); sp spy = new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT); - spy->setInputFeatures(WindowInfo::Feature::SPY); + spy->setSpy(true); spy->setTrustedOverlay(true); return spy; } @@ -6699,7 +6715,7 @@ public: overlay->setFocusable(false); overlay->setOwnerInfo(111, 111); overlay->setTouchable(false); - overlay->setInputFeatures(WindowInfo::Feature::INTERCEPTS_STYLUS); + overlay->setInterceptsStylus(true); overlay->setTrustedOverlay(true); std::shared_ptr application = @@ -6765,7 +6781,7 @@ TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) { TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) { auto [overlay, window] = setupStylusOverlayScenario(); - overlay->setInputFeatures(overlay->getInfo()->inputFeatures | WindowInfo::Feature::SPY); + overlay->setSpy(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); sendStylusEvent(AMOTION_EVENT_ACTION_DOWN); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 533acfdefe..2653d8cb5c 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2251,14 +2251,14 @@ gui::DropInputMode Layer::getDropInputMode() const { } void Layer::handleDropInputMode(gui::WindowInfo& info) const { - if (mDrawingState.inputInfo.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL)) { + if (mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL)) { return; } // Check if we need to drop input unconditionally gui::DropInputMode dropInputMode = getDropInputMode(); if (dropInputMode == gui::DropInputMode::ALL) { - info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy.", getDebugName()); return; } @@ -2271,7 +2271,7 @@ void Layer::handleDropInputMode(gui::WindowInfo& info) const { // Check if the parent has set an alpha on the layer sp parent = mDrawingParent.promote(); if (parent && parent->getAlpha() != 1.0_hf) { - info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(), static_cast(getAlpha())); } @@ -2279,7 +2279,7 @@ void Layer::handleDropInputMode(gui::WindowInfo& info) const { // Check if the parent has cropped the buffer Rect bufferSize = getCroppedBufferSize(getDrawingState()); if (!bufferSize.isValid()) { - info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED; + info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED; return; } @@ -2291,7 +2291,7 @@ void Layer::handleDropInputMode(gui::WindowInfo& info) const { bool croppedByParent = bufferInScreenSpace != Rect{mScreenBounds}; if (croppedByParent) { - info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT; ALOGV("Dropping input for %s as requested by policy because buffer is cropped by parent", getDebugName()); } else { @@ -2299,7 +2299,7 @@ void Layer::handleDropInputMode(gui::WindowInfo& info) const { // input if the window is obscured. This check should be done in surfaceflinger but the // logic currently resides in inputflinger. So pass the if_obscured check to input to only // drop input events if the window is obscured. - info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED; + info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED; } } @@ -2308,7 +2308,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp mDrawingState.inputInfo.name = getName(); mDrawingState.inputInfo.ownerUid = mOwnerUid; mDrawingState.inputInfo.ownerPid = mOwnerPid; - mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL; + mDrawingState.inputInfo.inputConfig |= WindowInfo::InputConfig::NO_INPUT_CHANNEL; mDrawingState.inputInfo.displayId = getLayerStack().id; } @@ -2336,7 +2336,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp // If the window will be blacked out on a display because the display does not have the secure // flag and the layer has the secure flag set, then drop input. if (!displayIsSecure && isSecure()) { - info.inputFeatures |= WindowInfo::Feature::DROP_INPUT; + info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT; } auto cropLayer = mDrawingState.touchableRegionCrop.promote(); -- cgit v1.2.3-59-g8ed1b From a18588206c240b34128bb27e3ac875af17fce7f2 Mon Sep 17 00:00:00 2001 From: Linus Tufvesson Date: Fri, 4 Mar 2022 09:32:07 +0000 Subject: Allow windowhandles with NO_INPUT_CHANNEL This allows container surfaces to be considered visible in InputDispatcher and prevent touches from passing through them. In particular this is used by ActivityRecordInputSink to block touches that would otherwise pass through the area available to the activity. Bug: 194480991 Bug: 222292477 Test: Manually tested that blocking still works Test: atest android.server.wm.WindowUntrustedTouchTest Test: atest InputSurfacesTest Change-Id: Icb419d6c61d63eeeda4b6a9ad725cd4829fd6fc8 --- libs/gui/tests/EndToEndNativeInputTest.cpp | 70 +++++++++++++++++++++--------- services/surfaceflinger/Layer.cpp | 3 +- 2 files changed, 51 insertions(+), 22 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index fcfe21bee2..e69fc7869d 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -76,16 +76,30 @@ static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 5s; class InputSurface { public: - InputSurface(const sp &sc, int width, int height) { + InputSurface(const sp &sc, int width, int height, bool noInputChannel = false) { mSurfaceControl = sc; mInputFlinger = getInputFlinger(); - mClientChannel = std::make_shared(); - mInputFlinger->createInputChannel("testchannels", mClientChannel.get()); + if (noInputChannel) { + mInputInfo.setInputConfig(WindowInfo::InputConfig::NO_INPUT_CHANNEL, true); + } else { + mClientChannel = std::make_shared(); + mInputFlinger->createInputChannel("testchannels", mClientChannel.get()); + mInputInfo.token = mClientChannel->getConnectionToken(); + mInputConsumer = new InputConsumer(mClientChannel); + } - populateInputInfo(width, height); + mInputInfo.name = "Test info"; + mInputInfo.dispatchingTimeout = 5s; + mInputInfo.globalScaleFactor = 1.0; + mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height)); - mInputConsumer = new InputConsumer(mClientChannel); + InputApplicationInfo aInfo; + aInfo.token = new BBinder(); + aInfo.name = "Test app info"; + aInfo.dispatchingTimeoutMillis = + std::chrono::duration_cast(DISPATCHING_TIMEOUT).count(); + mInputInfo.applicationInfo = aInfo; } static std::unique_ptr makeColorInputSurface(const sp &scc, @@ -114,6 +128,16 @@ public: return std::make_unique(surfaceControl, width, height); } + static std::unique_ptr makeContainerInputSurfaceNoInputChannel( + const sp &scc, int width, int height) { + sp surfaceControl = + scc->createSurface(String8("Test Container Surface"), 100 /* height */, + 100 /* width */, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceContainer); + return std::make_unique(surfaceControl, width, height, + true /* noInputChannel */); + } + static std::unique_ptr makeCursorInputSurface( const sp &scc, int width, int height) { sp surfaceControl = @@ -219,7 +243,9 @@ public: } virtual ~InputSurface() { - mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken()); + if (mClientChannel) { + mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken()); + } } virtual void doTransaction( @@ -263,21 +289,6 @@ private: poll(&fd, 1, timeoutMs); } - void populateInputInfo(int width, int height) { - mInputInfo.token = mClientChannel->getConnectionToken(); - mInputInfo.name = "Test info"; - mInputInfo.dispatchingTimeout = 5s; - mInputInfo.globalScaleFactor = 1.0; - mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height)); - - InputApplicationInfo aInfo; - aInfo.token = new BBinder(); - aInfo.name = "Test app info"; - aInfo.dispatchingTimeoutMillis = - std::chrono::duration_cast(DISPATCHING_TIMEOUT).count(); - - mInputInfo.applicationInfo = aInfo; - } public: sp mSurfaceControl; std::shared_ptr mClientChannel; @@ -1085,6 +1096,23 @@ TEST_F(InputSurfacesTest, replace_touchable_region_with_crop) { EXPECT_EQ(containerSurface->consumeEvent(100), nullptr); } +TEST_F(InputSurfacesTest, child_container_with_no_input_channel_blocks_parent) { + std::unique_ptr parent = makeSurface(100, 100); + + parent->showAt(100, 100); + injectTap(101, 101); + parent->expectTap(1, 1); + + std::unique_ptr childContainerSurface = + InputSurface::makeContainerInputSurfaceNoInputChannel(mComposerClient, 100, 100); + childContainerSurface->showAt(0, 0); + childContainerSurface->doTransaction( + [&](auto &t, auto &sc) { t.reparent(sc, parent->mSurfaceControl); }); + injectTap(101, 101); + + EXPECT_EQ(parent->consumeEvent(100), nullptr); +} + class MultiDisplayTests : public InputSurfacesTest { public: MultiDisplayTests() : InputSurfacesTest() { ProcessState::self()->startThreadPool(); } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index aeaf1e1a14..ac7bcde7a8 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2392,7 +2392,8 @@ sp Layer::getClonedRoot() { } bool Layer::hasInputInfo() const { - return mDrawingState.inputInfo.token != nullptr; + return mDrawingState.inputInfo.token != nullptr || + mDrawingState.inputInfo.inputConfig.test(WindowInfo::InputConfig::NO_INPUT_CHANNEL); } bool Layer::canReceiveInput() const { -- cgit v1.2.3-59-g8ed1b From f98655a3858df997251c0ae3bbb4262846dc9c8a Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 22 Mar 2022 16:07:03 +0000 Subject: Do not enforce that layers with invalid bounds are not focusable This is a partial revert of ag/16743825. We previously made this change to expect more strict preconditions for input windows, but are now running into app-compat issues. Since it is not essential, we no longer enforce that layers with invalid bounds are not focusable. Bug: 225029938 Test: atest libgui_test Test: manual with affected apps Change-Id: Ic70eebf991322adc93bd824528d8d87f892d01e1 --- libs/gui/tests/EndToEndNativeInputTest.cpp | 15 --------------- services/surfaceflinger/Layer.cpp | 1 - 2 files changed, 16 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index fcfe21bee2..e7ee20d19d 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -984,21 +984,6 @@ TEST_F(InputSurfacesTest, drop_input_policy) { EXPECT_EQ(surface->consumeEvent(100), nullptr); } -TEST_F(InputSurfacesTest, layer_with_empty_crop_cannot_be_focused) { - std::unique_ptr bufferSurface = - InputSurface::makeBufferInputSurface(mComposerClient, 100, 100); - - bufferSurface->showAt(50, 50, Rect::EMPTY_RECT); - - bufferSurface->requestFocus(); - EXPECT_EQ(bufferSurface->consumeEvent(100), nullptr); - - bufferSurface->showAt(50, 50, Rect::INVALID_RECT); - - bufferSurface->requestFocus(); - EXPECT_EQ(bufferSurface->consumeEvent(100), nullptr); -} - TEST_F(InputSurfacesTest, layer_with_valid_crop_can_be_focused) { std::unique_ptr bufferSurface = InputSurface::makeBufferInputSurface(mComposerClient, 100, 100); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index aeaf1e1a14..03258480c6 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2177,7 +2177,6 @@ Rect Layer::getInputBounds() const { void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) { Rect tmpBounds = getInputBounds(); if (!tmpBounds.isValid()) { - info.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, true); info.touchableRegion.clear(); // A layer could have invalid input bounds and still expect to receive touch input if it has // replaceTouchableRegionWithCrop. For that case, the input transform needs to be calculated -- cgit v1.2.3-59-g8ed1b From 88b85e1f9b2fb3cf1ab9da1967e1d454be2d5be0 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 21 Mar 2022 15:47:35 -0700 Subject: SurfaceFlinger: Detect Rel Z loops Telemetry indicates we are sometimes seeing crashes due to infinite recursion in isHiddenByPolicy. We detect this condition (relative Z loop) and add a helpful log. The performance impact should be minimal as relative Z is rare, and the traversal isn't doing any heavy work or sp<> promotion. Bug: 213420016 Bug: 195298154 Bug: 219774897 Test: Existing tests pass Change-Id: Ia11854654e99288c5846fe7c62ebabf37daeb139 --- services/surfaceflinger/Layer.cpp | 31 +++++++++++++++++++++++++++++++ services/surfaceflinger/Layer.h | 1 + 2 files changed, 32 insertions(+) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index aeaf1e1a14..8159150f85 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -833,6 +833,14 @@ bool Layer::setRelativeLayer(const sp& relativeToHandle, int32_t relati return false; } + if (CC_UNLIKELY(relative->usingRelativeZ(LayerVector::StateSet::Drawing)) && + (relative->mDrawingState.zOrderRelativeOf == this)) { + ALOGE("Detected relative layer loop between %s and %s", + mName.c_str(), relative->mName.c_str()); + ALOGE("Ignoring new call to set relative layer"); + return false; + } + mFlinger->mSomeChildrenChanged = true; mDrawingState.sequence++; @@ -1990,6 +1998,18 @@ void Layer::prepareShadowClientComposition(LayerFE::LayerSettings& caster, } } +bool Layer::findInHierarchy(const sp& l) { + if (l == this) { + return true; + } + for (auto& child : mDrawingChildren) { + if (child->findInHierarchy(l)) { + return true; + } + } + return false; +} + void Layer::commitChildList() { for (size_t i = 0; i < mCurrentChildren.size(); i++) { const auto& child = mCurrentChildren[i]; @@ -1997,6 +2017,17 @@ void Layer::commitChildList() { } mDrawingChildren = mCurrentChildren; mDrawingParent = mCurrentParent; + if (CC_UNLIKELY(usingRelativeZ(LayerVector::StateSet::Drawing))) { + auto zOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote(); + if (zOrderRelativeOf == nullptr) return; + if (findInHierarchy(zOrderRelativeOf)) { + ALOGE("Detected Z ordering loop between %s and %s", mName.c_str(), + zOrderRelativeOf->mName.c_str()); + ALOGE("Severing rel Z loop, potentially dangerous"); + mDrawingState.isRelativeOf = false; + zOrderRelativeOf->removeZOrderRelative(this); + } + } } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 48a9bc50c4..846460d4b1 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -1138,6 +1138,7 @@ private: bool mIsAtRoot = false; uint32_t mLayerCreationFlags; + bool findInHierarchy(const sp&); }; std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate); -- cgit v1.2.3-59-g8ed1b From 298b08e55a9c3846fcdb9c3d36802c04d1a941e7 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 15 Feb 2022 13:45:02 -0800 Subject: SF: Generalize thread safety guards Replace the guards with a uniform syntax that can be reused with annotations other than mStateLock and SF_MAIN_THREAD. Bug: 182939859 Test: Build Change-Id: I03e6fe5d465111a5882d2fc1c09fe1dc9660aa07 --- services/surfaceflinger/DisplayDevice.h | 24 +-- services/surfaceflinger/Layer.cpp | 7 +- services/surfaceflinger/MainThreadGuard.h | 35 --- services/surfaceflinger/MutexUtils.h | 53 +++++ services/surfaceflinger/SurfaceFlinger.cpp | 237 +++++++++------------ services/surfaceflinger/SurfaceFlinger.h | 14 +- services/surfaceflinger/ThreadContext.h | 25 +++ .../fuzzer/surfaceflinger_fuzzers_utils.h | 6 +- .../DisplayDevice_SetDisplayBrightnessTest.cpp | 7 +- 9 files changed, 202 insertions(+), 206 deletions(-) delete mode 100644 services/surfaceflinger/MainThreadGuard.h create mode 100644 services/surfaceflinger/MutexUtils.h create mode 100644 services/surfaceflinger/ThreadContext.h (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 2c4a300a0b..d5d87b40de 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -39,15 +41,11 @@ #include #include -#include "MainThreadGuard.h" - -#include #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/Hal.h" #include "DisplayHardware/PowerAdvisor.h" - #include "Scheduler/RefreshRateConfigs.h" - +#include "ThreadContext.h" #include "TracedOrdinal.h" namespace android { @@ -99,9 +97,9 @@ public: void setLayerStack(ui::LayerStack); void setDisplaySize(int width, int height); void setProjection(ui::Rotation orientation, Rect viewport, Rect frame); - void stageBrightness(float brightness) REQUIRES(SF_MAIN_THREAD); - void persistBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD); - bool isBrightnessStale() const REQUIRES(SF_MAIN_THREAD); + void stageBrightness(float brightness) REQUIRES(kMainThreadContext); + void persistBrightness(bool needsComposite) REQUIRES(kMainThreadContext); + bool isBrightnessStale() const REQUIRES(kMainThreadContext); void setFlags(uint32_t flags); ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; } @@ -109,7 +107,7 @@ public: static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags(); - std::optional getStagedBrightness() const REQUIRES(SF_MAIN_THREAD); + std::optional getStagedBrightness() const REQUIRES(kMainThreadContext); ui::Transform::RotationFlags getTransformHint() const; const ui::Transform& getTransform() const; const Rect& getLayerStackSpaceRect() const; @@ -209,15 +207,15 @@ public: bool setDesiredActiveMode(const ActiveModeInfo&) EXCLUDES(mActiveModeLock); std::optional getDesiredActiveMode() const EXCLUDES(mActiveModeLock); void clearDesiredActiveModeState() EXCLUDES(mActiveModeLock); - ActiveModeInfo getUpcomingActiveMode() const REQUIRES(SF_MAIN_THREAD) { + ActiveModeInfo getUpcomingActiveMode() const REQUIRES(kMainThreadContext) { return mUpcomingActiveMode; } - void setActiveMode(DisplayModeId) REQUIRES(SF_MAIN_THREAD); + void setActiveMode(DisplayModeId) REQUIRES(kMainThreadContext); status_t initiateModeChange(const ActiveModeInfo&, const hal::VsyncPeriodChangeConstraints& constraints, hal::VsyncPeriodChangeTimeline* outTimeline) - REQUIRES(SF_MAIN_THREAD); + REQUIRES(kMainThreadContext); // Return the immutable list of supported display modes. The HWC may report different modes // after a hotplug reconnect event, in which case the DisplayDevice object will be recreated. @@ -304,7 +302,7 @@ private: ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock); TracedOrdinal mDesiredActiveModeChanged GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false}; - ActiveModeInfo mUpcomingActiveMode GUARDED_BY(SF_MAIN_THREAD); + ActiveModeInfo mUpcomingActiveMode GUARDED_BY(kMainThreadContext); }; struct DisplayDeviceState { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index fa5a1c82ba..894fb8d47b 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -2045,10 +2046,10 @@ LayerProto* Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags) { writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags); if (traceFlags & LayerTracing::TRACE_COMPOSITION) { + ftl::FakeGuard guard(mFlinger->mStateLock); // Called from the main thread. + // Only populate for the primary display. - UnnecessaryLock assumeLocked(mFlinger->mStateLock); // called from the main thread. - const auto display = mFlinger->getDefaultDisplayDeviceLocked(); - if (display) { + if (const auto display = mFlinger->getDefaultDisplayDeviceLocked()) { const auto compositionType = getCompositionType(*display); layerProto->set_hwc_composition_type(static_cast(compositionType)); LayerProtoHelper::writeToProto(getVisibleRegion(display.get()), diff --git a/services/surfaceflinger/MainThreadGuard.h b/services/surfaceflinger/MainThreadGuard.h deleted file mode 100644 index c1aa118492..0000000000 --- a/services/surfaceflinger/MainThreadGuard.h +++ /dev/null @@ -1,35 +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 - -namespace android { -namespace { - -// Helps to ensure that some functions runs on SF's main thread by using the -// clang thread safety annotations. -class CAPABILITY("mutex") MainThreadGuard { -} SF_MAIN_THREAD; - -struct SCOPED_CAPABILITY MainThreadScopedGuard { -public: - explicit MainThreadScopedGuard(MainThreadGuard& mutex) ACQUIRE(mutex) {} - ~MainThreadScopedGuard() RELEASE() {} -}; -} // namespace -} // namespace android diff --git a/services/surfaceflinger/MutexUtils.h b/services/surfaceflinger/MutexUtils.h new file mode 100644 index 0000000000..f8be6f3b85 --- /dev/null +++ b/services/surfaceflinger/MutexUtils.h @@ -0,0 +1,53 @@ +/* + * Copyright 2022 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 { + +struct SCOPED_CAPABILITY ConditionalLock { + ConditionalLock(Mutex& mutex, bool lock) ACQUIRE(mutex) : mutex(mutex), lock(lock) { + if (lock) mutex.lock(); + } + + ~ConditionalLock() RELEASE() { + if (lock) mutex.unlock(); + } + + Mutex& mutex; + const bool lock; +}; + +struct SCOPED_CAPABILITY TimedLock { + TimedLock(Mutex& mutex, nsecs_t timeout, const char* whence) ACQUIRE(mutex) + : mutex(mutex), status(mutex.timedLock(timeout)) { + ALOGE_IF(!locked(), "%s timed out locking: %s (%d)", whence, strerror(-status), status); + } + + ~TimedLock() RELEASE() { + if (locked()) mutex.unlock(); + } + + bool locked() const { return status == NO_ERROR; } + + Mutex& mutex; + const status_t status; +}; + +} // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9f5a7df3aa..4fc9d273fc 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -24,7 +24,10 @@ #include "SurfaceFlinger.h" +#include #include +#include +#include #include #include #include @@ -49,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -123,6 +127,7 @@ #include "LayerRenderArea.h" #include "LayerVector.h" #include "MonitoredProducer.h" +#include "MutexUtils.h" #include "NativeWindowSurface.h" #include "RefreshRateOverlay.h" #include "RegionSamplingThread.h" @@ -138,49 +143,26 @@ #include "TimeStats/TimeStats.h" #include "TunnelModeEnabledReporter.h" #include "WindowInfosListenerInvoker.h" -#include "android-base/parseint.h" -#include "android-base/stringprintf.h" -#include "android-base/strings.h" #include #include -#define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock) - -// Note: The parentheses around `expr` are needed to deduce an lvalue or rvalue reference. -#define ON_MAIN_THREAD(expr) \ - [&]() -> decltype(auto) { \ - LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \ - UnnecessaryLock lock(mStateLock); \ - return (expr); \ - }() - -#define MAIN_THREAD_GUARD(expr) \ - [&]() -> decltype(auto) { \ - LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \ - MainThreadScopedGuard lock(SF_MAIN_THREAD); \ - return (expr); \ - }() - #undef NO_THREAD_SAFETY_ANALYSIS #define NO_THREAD_SAFETY_ANALYSIS \ - _Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"") - -using aidl::android::hardware::graphics::common::DisplayDecorationSupport; -using aidl::android::hardware::graphics::composer3::Capability; -using aidl::android::hardware::graphics::composer3::DisplayCapability; -using KernelIdleTimerController = - ::android::scheduler::RefreshRateConfigs::KernelIdleTimerController; + _Pragma("GCC error \"Prefer or MutexUtils.h helpers.\"") namespace android { using namespace std::string_literals; -using namespace android::hardware::configstore; -using namespace android::hardware::configstore::V1_0; -using namespace android::sysprop; +using namespace hardware::configstore; +using namespace hardware::configstore::V1_0; +using namespace sysprop; + +using aidl::android::hardware::graphics::common::DisplayDecorationSupport; +using aidl::android::hardware::graphics::composer3::Capability; +using aidl::android::hardware::graphics::composer3::DisplayCapability; -using android::hardware::power::Boost; using base::StringAppendF; using gui::DisplayInfo; using gui::IDisplayEventConnection; @@ -191,6 +173,8 @@ using ui::Dataspace; using ui::DisplayPrimaries; using ui::RenderIntent; +using KernelIdleTimerController = scheduler::RefreshRateConfigs::KernelIdleTimerController; + namespace hal = android::hardware::graphics::composer::hal; namespace { @@ -222,38 +206,6 @@ bool isWideColorMode(const ColorMode colorMode) { #pragma clang diagnostic pop -template -struct SCOPED_CAPABILITY ConditionalLockGuard { - ConditionalLockGuard(Mutex& mutex, bool lock) ACQUIRE(mutex) : mutex(mutex), lock(lock) { - if (lock) mutex.lock(); - } - - ~ConditionalLockGuard() RELEASE() { - if (lock) mutex.unlock(); - } - - Mutex& mutex; - const bool lock; -}; - -using ConditionalLock = ConditionalLockGuard; - -struct SCOPED_CAPABILITY TimedLock { - TimedLock(Mutex& mutex, nsecs_t timeout, const char* whence) ACQUIRE(mutex) - : mutex(mutex), status(mutex.timedLock(timeout)) { - ALOGE_IF(!locked(), "%s timed out locking: %s (%d)", whence, strerror(-status), status); - } - - ~TimedLock() RELEASE() { - if (locked()) mutex.unlock(); - } - - bool locked() const { return status == NO_ERROR; } - - Mutex& mutex; - const status_t status; -}; - // TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity. constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV; @@ -735,7 +687,7 @@ void SurfaceFlinger::bootFinished() { mBootStage = BootStage::FINISHED; if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) { - ON_MAIN_THREAD(enableRefreshRateOverlay(true)); + FTL_FAKE_GUARD(mStateLock, enableRefreshRateOverlay(true)); } })); } @@ -936,8 +888,9 @@ status_t SurfaceFlinger::getSupportedFrameTimestamps( FrameEvent::DEQUEUE_READY, FrameEvent::RELEASE, }; - ConditionalLock _l(mStateLock, - std::this_thread::get_id() != mMainThreadId); + + ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); + if (!getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) { outSupported->push_back(FrameEvent::DISPLAY_PRESENT); } @@ -1142,7 +1095,7 @@ status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp& displayTok } auto future = mScheduler->schedule([=]() -> status_t { - const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken)); + const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken)); if (!display) { ALOGE("Attempt to set allowed display modes for invalid display token %p", displayToken.get()); @@ -1183,7 +1136,9 @@ void SurfaceFlinger::updateInternalStateWithChangedMode() { return; } - const auto upcomingModeInfo = MAIN_THREAD_GUARD(display->getUpcomingActiveMode()); + const auto upcomingModeInfo = + FTL_FAKE_GUARD(kMainThreadContext, display->getUpcomingActiveMode()); + if (!upcomingModeInfo.mode) { // There is no pending mode change. This can happen if the active // display changed and the mode change happened on a different display. @@ -1202,9 +1157,8 @@ void SurfaceFlinger::updateInternalStateWithChangedMode() { return; } - // We just created this display so we can call even if we are not on - // the main thread - MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD); + // We just created this display so we can call even if we are not on the main thread. + ftl::FakeGuard guard(kMainThreadContext); display->setActiveMode(upcomingModeInfo.mode->getId()); const Fps refreshRate = upcomingModeInfo.mode->getFps(); @@ -1289,8 +1243,10 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { constraints.seamlessRequired = false; hal::VsyncPeriodChangeTimeline outTimeline; - const auto status = MAIN_THREAD_GUARD( - display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline)); + const auto status = FTL_FAKE_GUARD(kMainThreadContext, + display->initiateModeChange(*desiredActiveMode, + constraints, &outTimeline)); + if (status != NO_ERROR) { // initiateModeChange may fail if a hotplug event is just about // to be sent. We just log the error in this case. @@ -1323,7 +1279,7 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { } void SurfaceFlinger::disableExpensiveRendering() { - auto future = mScheduler->schedule([=]() MAIN_THREAD { + auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { ATRACE_CALL(); if (mPowerAdvisor.isUsingExpensiveRendering()) { for (const auto& [_, display] : mDisplays) { @@ -1372,7 +1328,7 @@ status_t SurfaceFlinger::setActiveColorMode(const sp& displayToken, Col return BAD_VALUE; } - auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t { + auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t { const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p", @@ -1407,17 +1363,17 @@ status_t SurfaceFlinger::setActiveColorMode(const sp& displayToken, Col } status_t SurfaceFlinger::getBootDisplayModeSupport(bool* outSupport) const { - auto future = mScheduler->schedule([=]() MAIN_THREAD mutable -> status_t { - *outSupport = getHwComposer().hasCapability(Capability::BOOT_DISPLAY_CONFIG); - return NO_ERROR; - }); - return future.get(); + auto future = mScheduler->schedule( + [this] { return getHwComposer().hasCapability(Capability::BOOT_DISPLAY_CONFIG); }); + + *outSupport = future.get(); + return NO_ERROR; } status_t SurfaceFlinger::setBootDisplayMode(const sp& displayToken, ui::DisplayModeId modeId) { const char* const whence = __func__; - auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t { + auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t { const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("%s: Invalid display token %p", whence, displayToken.get()); @@ -1444,7 +1400,7 @@ status_t SurfaceFlinger::setBootDisplayMode(const sp& displayToken, status_t SurfaceFlinger::clearBootDisplayMode(const sp& displayToken) { const char* const whence = __func__; - auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t { + auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t { if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { return getHwComposer().clearBootDisplayMode(*displayId); } else { @@ -1457,7 +1413,7 @@ status_t SurfaceFlinger::clearBootDisplayMode(const sp& displayToken) { void SurfaceFlinger::setAutoLowLatencyMode(const sp& displayToken, bool on) { const char* const whence = __func__; - static_cast(mScheduler->schedule([=]() MAIN_THREAD { + static_cast(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { getHwComposer().setAutoLowLatencyMode(*displayId, on); } else { @@ -1468,7 +1424,7 @@ void SurfaceFlinger::setAutoLowLatencyMode(const sp& displayToken, bool void SurfaceFlinger::setGameContentType(const sp& displayToken, bool on) { const char* const whence = __func__; - static_cast(mScheduler->schedule([=]() MAIN_THREAD { + static_cast(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { const auto type = on ? hal::ContentType::GAME : hal::ContentType::NONE; getHwComposer().setContentType(*displayId, type); @@ -1533,7 +1489,7 @@ status_t SurfaceFlinger::setDisplayContentSamplingEnabled(const sp& dis bool enable, uint8_t componentMask, uint64_t maxFrames) { const char* const whence = __func__; - auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t { + auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t { if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { return getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable, componentMask, maxFrames); @@ -1610,7 +1566,7 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) { status_t SurfaceFlinger::getLayerDebugInfo(std::vector* outLayers) { outLayers->clear(); auto future = mScheduler->schedule([=] { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); mDrawingState.traverseInZOrder([&](Layer* layer) { outLayers->push_back(layer->getLayerDebugInfo(display.get())); }); @@ -1722,7 +1678,7 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, } const char* const whence = __func__; - return ftl::chain(mScheduler->schedule([=]() MAIN_THREAD { + return ftl::chain(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { if (const auto display = getDisplayDeviceLocked(displayToken)) { const bool supportsDisplayBrightnessCommand = getHwComposer().getComposer()->isSupported( @@ -1736,7 +1692,9 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, compositionDisplay->editState().displayBrightnessNits; compositionDisplay->setDisplayBrightness(brightness.sdrWhitePointNits, brightness.displayBrightnessNits); - MAIN_THREAD_GUARD(display->stageBrightness(brightness.displayBrightness)); + FTL_FAKE_GUARD(kMainThreadContext, + display->stageBrightness(brightness.displayBrightness)); + if (brightness.sdrWhitePointNits / brightness.displayBrightnessNits != currentDimmingRatio) { scheduleComposite(FrameHint::kNone); @@ -1806,6 +1764,7 @@ status_t SurfaceFlinger::removeHdrLayerInfoListener( } status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) { + using hardware::power::Boost; Boost powerBoost = static_cast(boostId); if (powerBoost == Boost::INTERACTION) { @@ -1966,7 +1925,7 @@ void SurfaceFlinger::setVsyncEnabled(bool enabled) { ATRACE_CALL(); // On main thread to avoid race conditions with display power state. - static_cast(mScheduler->schedule([=]() MAIN_THREAD { + static_cast(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { mHWCVsyncPendingState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE; if (const auto display = getDefaultDisplayDeviceLocked(); @@ -2014,8 +1973,8 @@ nsecs_t SurfaceFlinger::calculateExpectedPresentTime(DisplayStatInfo stats) cons : stats.vsyncTime + stats.vsyncPeriod; } -bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) { - MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD); +bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) + FTL_FAKE_GUARD(kMainThreadContext) { // we set this once at the beginning of commit to ensure consistency throughout the whole frame mPowerHintSessionData.sessionEnabled = mPowerAdvisor.usePowerHintSession(); if (mPowerHintSessionData.sessionEnabled) { @@ -2181,20 +2140,21 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected mLayerTracing.notify(mVisibleRegionsDirty, frameTime); } - MAIN_THREAD_GUARD(persistDisplayBrightness(mustComposite)); + persistDisplayBrightness(mustComposite); return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER); } -void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) { +void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) + FTL_FAKE_GUARD(kMainThreadContext) { ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId); - MainThreadScopedGuard mainThreadGuard(SF_MAIN_THREAD); + if (mPowerHintSessionData.sessionEnabled) { mPowerHintSessionData.compositeStart = systemTime(); } compositionengine::CompositionRefreshArgs refreshArgs; - const auto& displays = ON_MAIN_THREAD(mDisplays); + const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays); refreshArgs.outputs.reserve(displays.size()); for (const auto& [_, display] : displays) { refreshArgs.outputs.push_back(display->getCompositionDisplay()); @@ -2432,7 +2392,7 @@ void SurfaceFlinger::postComposition() { ATRACE_CALL(); ALOGV("postComposition"); - const auto* display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()).get(); + const auto* display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get(); getBE().mGlCompositionDoneTimeline.updateSignalTimes(); std::shared_ptr glCompositionDoneFenceTime; @@ -2632,44 +2592,37 @@ void SurfaceFlinger::postComposition() { } FloatRect SurfaceFlinger::getMaxDisplayBounds() { - // Find the largest width and height among all the displays. - int32_t maxDisplayWidth = 0; - int32_t maxDisplayHeight = 0; - - // If there are no displays, set a valid display bounds so we can still compute a valid layer - // bounds. - if (ON_MAIN_THREAD(mDisplays.size()) == 0) { - maxDisplayWidth = maxDisplayHeight = 5000; - } - - for (const auto& pair : ON_MAIN_THREAD(mDisplays)) { - const auto& displayDevice = pair.second; - int32_t width = displayDevice->getWidth(); - int32_t height = displayDevice->getHeight(); - if (width > maxDisplayWidth) { - maxDisplayWidth = width; - } - if (height > maxDisplayHeight) { - maxDisplayHeight = height; - } - } + const ui::Size maxSize = [this] { + ftl::FakeGuard guard(mStateLock); + + // The LayerTraceGenerator tool runs without displays. + if (mDisplays.empty()) return ui::Size{5000, 5000}; + + return std::accumulate(mDisplays.begin(), mDisplays.end(), ui::kEmptySize, + [](ui::Size size, const auto& pair) -> ui::Size { + const auto& display = pair.second; + return {std::max(size.getWidth(), display->getWidth()), + std::max(size.getHeight(), display->getHeight())}; + }); + }(); // Ignore display bounds for now since they will be computed later. Use a large Rect bound // to ensure it's bigger than an actual display will be. - FloatRect maxBounds = FloatRect(-maxDisplayWidth * 10, -maxDisplayHeight * 10, - maxDisplayWidth * 10, maxDisplayHeight * 10); - return maxBounds; + const float xMax = maxSize.getWidth() * 10.f; + const float yMax = maxSize.getHeight() * 10.f; + + return {-xMax, -yMax, xMax, yMax}; } void SurfaceFlinger::computeLayerBounds() { - FloatRect maxBounds = getMaxDisplayBounds(); + const FloatRect maxBounds = getMaxDisplayBounds(); for (const auto& layer : mDrawingState.layersSortedByZ) { layer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */); } } void SurfaceFlinger::postFrame() { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); if (display && getHwComposer().isConnected(display->getPhysicalId())) { uint32_t flipCount = display->getPageFlipCount(); if (flipCount % LOG_FRAME_STATS_PERIOD == 0) { @@ -2923,7 +2876,8 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); if (!state.isVirtual()) { - MAIN_THREAD_GUARD(display->setActiveMode(state.physical->activeMode->getId())); + FTL_FAKE_GUARD(kMainThreadContext, + display->setActiveMode(state.physical->activeMode->getId())); display->setDeviceProductInfo(state.physical->deviceProductInfo); } @@ -3293,7 +3247,7 @@ void SurfaceFlinger::persistDisplayBrightness(bool needsComposite) { return; } - for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { + for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { if (const auto brightness = display->getStagedBrightness(); brightness) { if (!needsComposite) { const status_t error = @@ -3316,7 +3270,7 @@ void SurfaceFlinger::buildWindowInfos(std::vector& outWindowInfos, std::vector& outDisplayInfos) { ftl::SmallMap displayInputInfos; - for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { + for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { const auto layerStack = display->getLayerStack(); const auto info = display->getInputInfo(); @@ -3361,7 +3315,7 @@ void SurfaceFlinger::buildWindowInfos(std::vector& outWindowInfos, void SurfaceFlinger::updateCursorAsync() { compositionengine::CompositionRefreshArgs refreshArgs; - for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { + for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { if (HalDisplayId::tryCast(display->getId())) { refreshArgs.outputs.push_back(display->getCompositionDisplay()); } @@ -3546,7 +3500,7 @@ void SurfaceFlinger::commitOffscreenLayers() { } void SurfaceFlinger::invalidateLayerStack(const sp& layer, const Region& dirty) { - for (const auto& [token, displayDevice] : ON_MAIN_THREAD(mDisplays)) { + for (const auto& [token, displayDevice] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { auto display = displayDevice->getCompositionDisplay(); if (display->includesLayer(layer->getOutputFilter())) { display->editState().dirtyRegion.orSelf(dirty); @@ -4832,7 +4786,8 @@ void SurfaceFlinger::onInitializeDisplays() { void SurfaceFlinger::initializeDisplays() { // Async since we may be called from the main thread. - static_cast(mScheduler->schedule([this]() MAIN_THREAD { onInitializeDisplays(); })); + static_cast( + mScheduler->schedule([this]() FTL_FAKE_GUARD(mStateLock) { onInitializeDisplays(); })); } void SurfaceFlinger::setPowerModeInternal(const sp& display, hal::PowerMode mode) { @@ -4932,7 +4887,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: } void SurfaceFlinger::setPowerMode(const sp& displayToken, int mode) { - auto future = mScheduler->schedule([=]() MAIN_THREAD { + auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set power mode %d for invalid display token %p", mode, @@ -4979,7 +4934,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { bool dumpLayers = true; { - TimedLock lock(mStateLock, s2ns(1), __FUNCTION__); + TimedLock lock(mStateLock, s2ns(1), __func__); if (!lock.locked()) { StringAppendF(&result, "Dumping without lock after timeout: %s (%d)\n", strerror(-lock.status), lock.status); @@ -5067,8 +5022,6 @@ void SurfaceFlinger::dumpFrameTimeline(const DumpArgs& args, std::string& result mFrameTimeline->parseArgs(args, result); } -// This should only be called from the main thread. Otherwise it would need -// the lock and should use mCurrentState rather than mDrawingState. void SurfaceFlinger::logFrameStats() { mDrawingState.traverse([&](Layer* layer) { layer->logFrameStats(); @@ -5226,7 +5179,7 @@ LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { } void SurfaceFlinger::dumpDisplayProto(LayersTraceProto& layersTraceProto) const { - for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { + for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { DisplayProto* displayProto = layersTraceProto.add_displays(); displayProto->set_id(display->getId().value); displayProto->set_name(display->getDisplayName()); @@ -5867,7 +5820,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r int64_t startingTime = (fixedStartingTime) ? fixedStartingTime : systemTime(); mScheduler - ->schedule([&]() MAIN_THREAD { + ->schedule([&]() FTL_FAKE_GUARD(mStateLock) { mLayerTracing.notify("start", startingTime); }) .wait(); @@ -5980,10 +5933,12 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r switch (n = data.readInt32()) { case 0: case 1: - ON_MAIN_THREAD(enableRefreshRateOverlay(static_cast(n))); + FTL_FAKE_GUARD(mStateLock, + enableRefreshRateOverlay(static_cast(n))); break; default: { - reply->writeBool(ON_MAIN_THREAD(isRefreshRateOverlayEnabled())); + reply->writeBool( + FTL_FAKE_GUARD(mStateLock, isRefreshRateOverlayEnabled())); } } }); @@ -6021,7 +5976,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return mScheduler ->schedule([this] { const auto display = - ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); // This is a little racy, but not in a way that hurts anything. As // we grab the defaultMode from the display manager policy, we could @@ -6043,7 +5998,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return mScheduler ->schedule([this] { const auto display = - ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); constexpr bool kOverridePolicy = true; return setDesiredDisplayModeSpecsInternal(display, {}, kOverridePolicy); @@ -6159,7 +6114,7 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { // Update the overlay on the main thread to avoid race conditions with // mRefreshRateConfigs->getActiveMode() static_cast(mScheduler->schedule([=] { - const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); if (!display) { ALOGW("%s: default display is null", __func__); return; @@ -6957,7 +6912,7 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecs( } auto future = mScheduler->schedule([=]() -> status_t { - const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken)); + const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken)); if (!display) { ALOGE("Attempt to set desired display modes for invalid display token %p", displayToken.get()); @@ -7202,7 +7157,7 @@ uint32_t SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t ui if (const auto frameRateOverride = mScheduler->getFrameRateOverride(uid)) { refreshRate = *frameRateOverride; } else if (!getHwComposer().isHeadless()) { - if (const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked())) { + if (const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked())) { refreshRate = display->refreshRateConfigs().getActiveMode()->getFps(); } } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f2636b446f..97b0e8db5c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -64,6 +64,7 @@ #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncModulator.h" #include "SurfaceFlingerFactory.h" +#include "ThreadContext.h" #include "TracedOrdinal.h" #include "Tracing/LayerTracing.h" #include "Tracing/TransactionTracing.h" @@ -183,11 +184,6 @@ struct SurfaceFlingerBE { std::atomic mLastSwapTime = 0; }; -struct SCOPED_CAPABILITY UnnecessaryLock { - explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {} - ~UnnecessaryLock() RELEASE() {} -}; - class SurfaceFlinger : public BnSurfaceComposer, public PriorityDumper, private IBinder::DeathRecipient, @@ -740,7 +736,7 @@ private: void updateLayerGeometry(); void updateInputFlinger(); - void persistDisplayBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD); + void persistDisplayBrightness(bool needsComposite) REQUIRES(kMainThreadContext); void buildWindowInfos(std::vector& outWindowInfos, std::vector& outDisplayInfos); void commitInputWindowCommands() REQUIRES(mStateLock); @@ -973,7 +969,7 @@ private: void setCompositorTimingSnapped(const DisplayStatInfo& stats, nsecs_t compositeToPresentLatency); - void postFrame(); + void postFrame() REQUIRES(kMainThreadContext); /* * Display management @@ -1088,7 +1084,7 @@ private: void clearStatsLocked(const DumpArgs& args, std::string& result); void dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const; void dumpFrameTimeline(const DumpArgs& args, std::string& result) const; - void logFrameStats(); + void logFrameStats() REQUIRES(kMainThreadContext); void dumpVSync(std::string& result) const REQUIRES(mStateLock); void dumpStaticScreenStats(std::string& result) const; @@ -1431,7 +1427,7 @@ private: nsecs_t commitStart; nsecs_t compositeStart; nsecs_t presentEnd; - } mPowerHintSessionData GUARDED_BY(SF_MAIN_THREAD); + } mPowerHintSessionData GUARDED_BY(kMainThreadContext); nsecs_t mAnimationTransactionTimeout = s2ns(5); diff --git a/services/surfaceflinger/ThreadContext.h b/services/surfaceflinger/ThreadContext.h new file mode 100644 index 0000000000..85c379d58f --- /dev/null +++ b/services/surfaceflinger/ThreadContext.h @@ -0,0 +1,25 @@ +/* + * Copyright 2022 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 + +namespace android { + +// Enforces exclusive access by the main thread. +constexpr class [[clang::capability("mutex")]] { +} kMainThreadContext; + +} // namespace android diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 1d0f62b99b..a80aca2f73 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,7 @@ #include "SurfaceFlinger.h" #include "SurfaceFlingerDefaultFactory.h" #include "SurfaceInterceptor.h" +#include "ThreadContext.h" #include "TimeStats/TimeStats.h" #include "renderengine/mock/RenderEngine.h" @@ -445,7 +447,7 @@ public: mFlinger->clearStatsLocked(dumpArgs, result); mFlinger->dumpTimeStats(dumpArgs, fdp->ConsumeBool(), result); - mFlinger->logFrameStats(); + FTL_FAKE_GUARD(kMainThreadContext, mFlinger->logFrameStats()); result = fdp->ConsumeRandomLengthString().c_str(); mFlinger->dumpFrameTimeline(dumpArgs, result); @@ -651,7 +653,7 @@ public: updateCompositorTiming(&mFdp); mFlinger->setCompositorTimingSnapped({}, mFdp.ConsumeIntegral()); - mFlinger->postFrame(); + FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postFrame()); mFlinger->calculateExpectedPresentTime({}); mFlinger->enableHalVirtualDisplays(mFdp.ConsumeBool()); diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp index 73c60e1035..225ad163d9 100644 --- a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp @@ -19,6 +19,7 @@ #include "DisplayTransactionTestHelpers.h" +#include #include #include @@ -35,7 +36,7 @@ public: }; TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessNoComposite) { - MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD); + ftl::FakeGuard guard(kMainThreadContext); sp displayDevice = getDisplayDevice(); EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); @@ -52,7 +53,7 @@ TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessNoComposite) { } TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithComposite) { - MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD); + ftl::FakeGuard guard(kMainThreadContext); sp displayDevice = getDisplayDevice(); EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); @@ -70,7 +71,7 @@ TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithComposite) { } TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithCompositeShortCircuitsOnNoOp) { - MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD); + ftl::FakeGuard guard(kMainThreadContext); sp displayDevice = getDisplayDevice(); EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); -- cgit v1.2.3-59-g8ed1b From 81d95e6534106159210a768268fd77f21139e7a9 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Mon, 21 Mar 2022 19:41:33 -0700 Subject: [SurfaceFlinger] Disable HDR dimming when screen rotates. - Disable dimming for screenshot layer Bug: 224860402 Test: check HDR vidoes when rotation, atest libcompositionengine_test Change-Id: Ib07a5af1d4e3e91737b3d5f3e5869c166759563f Merged-In: Ib07a5af1d4e3e91737b3d5f3e5869c166759563f --- libs/gui/LayerState.cpp | 6 ++++++ libs/gui/SurfaceComposerClient.cpp | 14 ++++++++++++++ libs/gui/include/gui/LayerState.h | 6 ++++-- libs/gui/include/gui/SurfaceComposerClient.h | 1 + services/surfaceflinger/BufferStateLayer.cpp | 7 +++++++ .../include/compositionengine/LayerFECompositionState.h | 3 +++ .../CompositionEngine/src/LayerFECompositionState.cpp | 1 + .../surfaceflinger/CompositionEngine/src/OutputLayer.cpp | 3 ++- .../CompositionEngine/tests/OutputLayerTest.cpp | 7 +++++++ services/surfaceflinger/Layer.cpp | 12 ++++++++++++ services/surfaceflinger/Layer.h | 4 ++++ services/surfaceflinger/SurfaceFlinger.cpp | 3 +++ 12 files changed, 64 insertions(+), 3 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 34db5b1626..304fc17e07 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -134,6 +134,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeByte, changeFrameRateStrategy); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeBool, autoRefresh); + SAFE_PARCEL(output.writeBool, dimmingEnabled); SAFE_PARCEL(output.writeUint32, blurRegions.size()); for (auto region : blurRegions) { @@ -243,6 +244,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readBool, &autoRefresh); + SAFE_PARCEL(input.readBool, &dimmingEnabled); uint32_t numRegions = 0; SAFE_PARCEL(input.readUint32, &numRegions); @@ -598,6 +600,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eColorSpaceAgnosticChanged; colorSpaceAgnostic = other.colorSpaceAgnostic; } + if (other.what & eDimmingEnabledChanged) { + what |= eDimmingEnabledChanged; + dimmingEnabled = other.dimmingEnabled; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIX64 " what=0x%" PRIX64 " unmerged flags=0x%" PRIX64, diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 52a22a77fd..6c197c457c 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1195,6 +1195,20 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrans return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDimmingEnabled( + const sp& sc, bool dimmingEnabled) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eDimmingEnabledChanged; + s->dimmingEnabled = dimmingEnabled; + + registerSurfaceControlForCallback(sc); + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha( const sp& sc, float alpha) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 0f37dab53c..4ca8d68142 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -150,7 +150,7 @@ struct layer_state_t { eTransparentRegionChanged = 0x00000020, eFlagsChanged = 0x00000040, eLayerStackChanged = 0x00000080, - /* unused 0x00000400, */ + eDimmingEnabledChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, /* unused 0x00001000, */ eBufferCropChanged = 0x00002000, @@ -187,7 +187,7 @@ struct layer_state_t { eAutoRefreshChanged = 0x1000'00000000, eStretchChanged = 0x2000'00000000, eTrustedOverlayChanged = 0x4000'00000000, - eDropInputModeChanged = 0x8000'00000000, + eDropInputModeChanged = 0x8000'00000000 }; layer_state_t(); @@ -298,6 +298,8 @@ struct layer_state_t { // Force inputflinger to drop all input events for the layer and its children. gui::DropInputMode dropInputMode; + + bool dimmingEnabled; }; struct ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 9d03f58aa5..0cc43d85bf 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -491,6 +491,7 @@ public: uint32_t flags, uint32_t mask); Transaction& setTransparentRegionHint(const sp& sc, const Region& transparentRegion); + Transaction& setDimmingEnabled(const sp& sc, bool dimmingEnabled); Transaction& setAlpha(const sp& sc, float alpha); Transaction& setMatrix(const sp& sc, diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index bcae8d9564..c5d7a601c5 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -1098,6 +1098,13 @@ bool BufferStateLayer::simpleBufferUpdate(const layer_state_t& s) const { } } + if (s.what & layer_state_t::eDimmingEnabledChanged) { + if (mDrawingState.dimmingEnabled != s.dimmingEnabled) { + ALOGV("%s: false [eDimmingEnabledChanged changed]", __func__); + return false; + } + } + ALOGV("%s: true", __func__); return true; } diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 283fe86f43..974f7c6134 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -207,6 +207,9 @@ struct LayerFECompositionState { // framerate of the layer as measured by LayerHistory float fps; + // The dimming flag + bool dimmingEnabled{true}; + virtual ~LayerFECompositionState(); // Debugging diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp index ff7d430531..6631a2772c 100644 --- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp @@ -121,6 +121,7 @@ void LayerFECompositionState::dump(std::string& out) const { dumpVal(out, "isColorspaceAgnostic", isColorspaceAgnostic); dumpVal(out, "dataspace", toString(dataspace), dataspace); dumpVal(out, "hdr metadata types", hdrMetadata.validTypes); + dumpVal(out, "dimming enabled", dimmingEnabled); dumpVal(out, "colorTransform", colorTransform); out.append("\n"); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 723593d7ac..3289d55870 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -324,9 +324,10 @@ void OutputLayer::updateCompositionState( // For hdr content, treat the white point as the display brightness - HDR content should not be // boosted or dimmed. + // If the layer explicitly requests to disable dimming, then don't dim either. if (isHdrDataspace(state.dataspace) || getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits || - getOutput().getState().displayBrightnessNits == 0.f) { + getOutput().getState().displayBrightnessNits == 0.f || !layerFEState->dimmingEnabled) { state.dimmingRatio = 1.f; state.whitePointNits = getOutput().getState().displayBrightnessNits; } else { diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 8eb1946b67..ceee48c1ef 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -668,6 +668,13 @@ TEST_F(OutputLayerUpdateCompositionStateTest, setsWhitePointNitsAndDimmingRatioC EXPECT_EQ(mOutputState.sdrWhitePointNits / mOutputState.displayBrightnessNits, mOutputLayer.getState().dimmingRatio); + mLayerFEState.dimmingEnabled = false; + mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0); + EXPECT_EQ(mOutputState.displayBrightnessNits, mOutputLayer.getState().whitePointNits); + EXPECT_EQ(1.f, mOutputLayer.getState().dimmingRatio); + + // change dimmingEnabled back to true. + mLayerFEState.dimmingEnabled = true; mLayerFEState.dataspace = ui::Dataspace::BT2020_ITU_PQ; mLayerFEState.isColorspaceAgnostic = false; mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 894fb8d47b..3d00b90816 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -140,6 +140,7 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.destinationFrame.makeInvalid(); mDrawingState.isTrustedOverlay = false; mDrawingState.dropInputMode = gui::DropInputMode::NONE; + mDrawingState.dimmingEnabled = true; if (args.flags & ISurfaceComposerClient::eNoColorFill) { // Set an invalid color so there is no color fill. @@ -478,6 +479,7 @@ void Layer::preparePerFrameCompositionState() { compositionState->colorTransformIsIdentity = !hasColorTransform(); compositionState->surfaceDamage = surfaceDamageRegion; compositionState->hasProtectedContent = isProtected(); + compositionState->dimmingEnabled = isDimmingEnabled(); const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f; @@ -1039,6 +1041,16 @@ bool Layer::setColorSpaceAgnostic(const bool agnostic) { return true; } +bool Layer::setDimmingEnabled(const bool dimmingEnabled) { + if (mDrawingState.dimmingEnabled == dimmingEnabled) return false; + + mDrawingState.sequence++; + mDrawingState.dimmingEnabled = dimmingEnabled; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + bool Layer::setFrameRateSelectionPriority(int32_t priority) { if (mDrawingState.frameRateSelectionPriority == priority) return false; mDrawingState.frameRateSelectionPriority = priority; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 846460d4b1..565a6ff726 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -281,6 +281,8 @@ public: gui::DropInputMode dropInputMode; bool autoRefresh = false; + + bool dimmingEnabled = true; }; /* @@ -411,6 +413,7 @@ public: virtual mat4 getColorTransform() const; virtual bool hasColorTransform() const; virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; } + virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; }; // Used only to set BufferStateLayer state virtual bool setTransform(uint32_t /*transform*/) { return false; }; @@ -437,6 +440,7 @@ public: } virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace); virtual bool setColorSpaceAgnostic(const bool agnostic); + virtual bool setDimmingEnabled(const bool dimmingEnabled); virtual bool setFrameRateSelectionPriority(int32_t priority); virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint); virtual void setAutoRefresh(bool /* autoRefresh */) {} diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4fc9d273fc..78a26e15fe 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4488,6 +4488,9 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (what & layer_state_t::eAutoRefreshChanged) { layer->setAutoRefresh(s.autoRefresh); } + if (what & layer_state_t::eDimmingEnabledChanged) { + if (layer->setDimmingEnabled(s.dimmingEnabled)) flags |= eTraversalNeeded; + } if (what & layer_state_t::eTrustedOverlayChanged) { if (layer->setTrustedOverlay(s.isTrustedOverlay)) { flags |= eTraversalNeeded; -- cgit v1.2.3-59-g8ed1b From 2f01d772a56167b21b23c8dd4bfaa6cb5f667443 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 23 Mar 2022 16:01:29 -0700 Subject: FTL: Pull Flags into namespace Bug: 185536303 Test: Build Change-Id: Ia9aafc78565414815dfc14732ce85b06fa96e17b --- include/ftl/Flags.h | 225 --------------------- include/ftl/flags.h | 225 +++++++++++++++++++++ libs/ftl/Android.bp | 2 +- libs/ftl/Flags_test.cpp | 213 ------------------- libs/ftl/flags_test.cpp | 214 ++++++++++++++++++++ libs/gui/LayerState.cpp | 2 +- libs/gui/WindowInfo.cpp | 12 +- libs/gui/include/gui/ISurfaceComposer.h | 4 +- libs/gui/include/gui/LayerState.h | 3 +- libs/gui/include/gui/WindowInfo.h | 8 +- services/inputflinger/reader/EventHub.cpp | 14 +- services/inputflinger/reader/InputDevice.cpp | 7 +- services/inputflinger/reader/include/EventHub.h | 22 +- services/inputflinger/reader/include/InputDevice.h | 10 +- .../inputflinger/tests/InputDispatcher_test.cpp | 3 +- services/inputflinger/tests/InputReader_test.cpp | 97 ++++----- .../compositionengine/impl/planner/LayerState.h | 30 +-- .../compositionengine/impl/planner/Predictor.h | 4 +- .../CompositionEngine/src/planner/LayerState.cpp | 8 +- .../CompositionEngine/src/planner/Planner.cpp | 2 +- .../CompositionEngine/src/planner/Predictor.cpp | 2 +- .../tests/planner/LayerStateTest.cpp | 90 ++++----- .../DisplayHardware/VirtualDisplaySurface.cpp | 12 +- services/surfaceflinger/Layer.cpp | 6 +- .../Scheduler/include/scheduler/Features.h | 6 +- .../Tracing/TransactionProtoParser.cpp | 2 +- .../tests/unittests/EventThreadTest.cpp | 3 +- 27 files changed, 620 insertions(+), 606 deletions(-) delete mode 100644 include/ftl/Flags.h create mode 100644 include/ftl/flags.h delete mode 100644 libs/ftl/Flags_test.cpp create mode 100644 libs/ftl/flags_test.cpp (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/include/ftl/Flags.h b/include/ftl/Flags.h deleted file mode 100644 index db3d9ea5b9..0000000000 --- a/include/ftl/Flags.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include -#include - -// TODO(b/185536303): Align with FTL style and namespace. - -namespace android { - -/* A class for handling flags defined by an enum or enum class in a type-safe way. */ -template -class Flags { - // F must be an enum or its underlying type is undefined. Theoretically we could specialize this - // further to avoid this restriction but in general we want to encourage the use of enums - // anyways. - static_assert(std::is_enum_v, "Flags type must be an enum"); - using U = std::underlying_type_t; - -public: - constexpr Flags(F f) : mFlags(static_cast(f)) {} - constexpr Flags() : mFlags(0) {} - constexpr Flags(const Flags& f) : mFlags(f.mFlags) {} - - // Provide a non-explicit construct for non-enum classes since they easily convert to their - // underlying types (e.g. when used with bitwise operators). For enum classes, however, we - // should force them to be explicitly constructed from their underlying types to make full use - // of the type checker. - template - constexpr Flags(T t, std::enable_if_t, T>* = nullptr) : mFlags(t) {} - - template - explicit constexpr Flags(T t, std::enable_if_t, T>* = nullptr) - : mFlags(t) {} - - class Iterator { - using Bits = std::uint64_t; - static_assert(sizeof(U) <= sizeof(Bits)); - - public: - constexpr Iterator() = default; - Iterator(Flags flags) : mRemainingFlags(flags.mFlags) { (*this)++; } - - // Pre-fix ++ - Iterator& operator++() { - if (mRemainingFlags.none()) { - mCurrFlag = 0; - } else { - // TODO: Replace with std::countr_zero in C++20. - const Bits bit = static_cast(__builtin_ctzll(mRemainingFlags.to_ullong())); - mRemainingFlags.reset(static_cast(bit)); - mCurrFlag = static_cast(static_cast(1) << bit); - } - return *this; - } - - // Post-fix ++ - Iterator operator++(int) { - Iterator iter = *this; - ++*this; - return iter; - } - - bool operator==(Iterator other) const { - return mCurrFlag == other.mCurrFlag && mRemainingFlags == other.mRemainingFlags; - } - - bool operator!=(Iterator other) const { return !(*this == other); } - - F operator*() const { return F{mCurrFlag}; } - - // iterator traits - - // In the future we could make this a bidirectional const iterator instead of a forward - // iterator but it doesn't seem worth the added complexity at this point. This could not, - // however, be made a non-const iterator as assigning one flag to another is a non-sensical - // operation. - using iterator_category = std::input_iterator_tag; - using value_type = F; - // Per the C++ spec, because input iterators are not assignable the iterator's reference - // type does not actually need to be a reference. In fact, making it a reference would imply - // that modifying it would change the underlying Flags object, which is obviously wrong for - // the same reason this can't be a non-const iterator. - using reference = F; - using difference_type = void; - using pointer = void; - - private: - std::bitset mRemainingFlags; - U mCurrFlag = 0; - }; - - /* - * Tests whether the given flag is set. - */ - bool test(F flag) const { - U f = static_cast(flag); - return (f & mFlags) == f; - } - - /* Tests whether any of the given flags are set */ - bool any(Flags f) const { return (mFlags & f.mFlags) != 0; } - - /* Tests whether all of the given flags are set */ - bool all(Flags f) const { return (mFlags & f.mFlags) == f.mFlags; } - - Flags operator|(Flags rhs) const { return static_cast(mFlags | rhs.mFlags); } - Flags& operator|=(Flags rhs) { - mFlags = mFlags | rhs.mFlags; - return *this; - } - - Flags operator&(Flags rhs) const { return static_cast(mFlags & rhs.mFlags); } - Flags& operator&=(Flags rhs) { - mFlags = mFlags & rhs.mFlags; - return *this; - } - - Flags operator^(Flags rhs) const { return static_cast(mFlags ^ rhs.mFlags); } - Flags& operator^=(Flags rhs) { - mFlags = mFlags ^ rhs.mFlags; - return *this; - } - - Flags operator~() { return static_cast(~mFlags); } - - bool operator==(Flags rhs) const { return mFlags == rhs.mFlags; } - bool operator!=(Flags rhs) const { return !operator==(rhs); } - - Flags& operator=(const Flags& rhs) { - mFlags = rhs.mFlags; - return *this; - } - - inline Flags& clear(Flags f = static_cast(~static_cast(0))) { - return *this &= ~f; - } - - Iterator begin() const { return Iterator(*this); } - - Iterator end() const { return Iterator(); } - - /* - * Returns the stored set of flags. - * - * Note that this returns the underlying type rather than the base enum class. This is because - * the value is no longer necessarily a strict member of the enum since the returned value could - * be multiple enum variants OR'd together. - */ - U get() const { return mFlags; } - - std::string string() const { - std::string result; - bool first = true; - U unstringified = 0; - for (const F f : *this) { - if (const auto flagName = ftl::flag_name(f)) { - appendFlag(result, flagName.value(), first); - } else { - unstringified |= static_cast(f); - } - } - - if (unstringified != 0) { - constexpr auto radix = sizeof(U) == 1 ? ftl::Radix::kBin : ftl::Radix::kHex; - appendFlag(result, ftl::to_string(unstringified, radix), first); - } - - if (first) { - result += "0x0"; - } - - return result; - } - -private: - U mFlags; - - static void appendFlag(std::string& str, const std::string_view& flag, bool& first) { - if (first) { - first = false; - } else { - str += " | "; - } - str += flag; - } -}; - -// This namespace provides operator overloads for enum classes to make it easier to work with them -// as flags. In order to use these, add them via a `using namespace` declaration. -namespace flag_operators { - -template >> -inline Flags operator~(F f) { - return static_cast(~ftl::to_underlying(f)); -} - -template >> -Flags operator|(F lhs, F rhs) { - return static_cast(ftl::to_underlying(lhs) | ftl::to_underlying(rhs)); -} - -} // namespace flag_operators -} // namespace android diff --git a/include/ftl/flags.h b/include/ftl/flags.h new file mode 100644 index 0000000000..70aaa0e6dd --- /dev/null +++ b/include/ftl/flags.h @@ -0,0 +1,225 @@ +/* + * 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 +#include + +// TODO(b/185536303): Align with FTL style. + +namespace android::ftl { + +/* A class for handling flags defined by an enum or enum class in a type-safe way. */ +template +class Flags { + // F must be an enum or its underlying type is undefined. Theoretically we could specialize this + // further to avoid this restriction but in general we want to encourage the use of enums + // anyways. + static_assert(std::is_enum_v, "Flags type must be an enum"); + using U = std::underlying_type_t; + +public: + constexpr Flags(F f) : mFlags(static_cast(f)) {} + constexpr Flags() : mFlags(0) {} + constexpr Flags(const Flags& f) : mFlags(f.mFlags) {} + + // Provide a non-explicit construct for non-enum classes since they easily convert to their + // underlying types (e.g. when used with bitwise operators). For enum classes, however, we + // should force them to be explicitly constructed from their underlying types to make full use + // of the type checker. + template + constexpr Flags(T t, std::enable_if_t, T>* = nullptr) : mFlags(t) {} + + template + explicit constexpr Flags(T t, std::enable_if_t, T>* = nullptr) + : mFlags(t) {} + + class Iterator { + using Bits = std::uint64_t; + static_assert(sizeof(U) <= sizeof(Bits)); + + public: + constexpr Iterator() = default; + Iterator(Flags flags) : mRemainingFlags(flags.mFlags) { (*this)++; } + + // Pre-fix ++ + Iterator& operator++() { + if (mRemainingFlags.none()) { + mCurrFlag = 0; + } else { + // TODO: Replace with std::countr_zero in C++20. + const Bits bit = static_cast(__builtin_ctzll(mRemainingFlags.to_ullong())); + mRemainingFlags.reset(static_cast(bit)); + mCurrFlag = static_cast(static_cast(1) << bit); + } + return *this; + } + + // Post-fix ++ + Iterator operator++(int) { + Iterator iter = *this; + ++*this; + return iter; + } + + bool operator==(Iterator other) const { + return mCurrFlag == other.mCurrFlag && mRemainingFlags == other.mRemainingFlags; + } + + bool operator!=(Iterator other) const { return !(*this == other); } + + F operator*() const { return F{mCurrFlag}; } + + // iterator traits + + // In the future we could make this a bidirectional const iterator instead of a forward + // iterator but it doesn't seem worth the added complexity at this point. This could not, + // however, be made a non-const iterator as assigning one flag to another is a non-sensical + // operation. + using iterator_category = std::input_iterator_tag; + using value_type = F; + // Per the C++ spec, because input iterators are not assignable the iterator's reference + // type does not actually need to be a reference. In fact, making it a reference would imply + // that modifying it would change the underlying Flags object, which is obviously wrong for + // the same reason this can't be a non-const iterator. + using reference = F; + using difference_type = void; + using pointer = void; + + private: + std::bitset mRemainingFlags; + U mCurrFlag = 0; + }; + + /* + * Tests whether the given flag is set. + */ + bool test(F flag) const { + U f = static_cast(flag); + return (f & mFlags) == f; + } + + /* Tests whether any of the given flags are set */ + bool any(Flags f) const { return (mFlags & f.mFlags) != 0; } + + /* Tests whether all of the given flags are set */ + bool all(Flags f) const { return (mFlags & f.mFlags) == f.mFlags; } + + Flags operator|(Flags rhs) const { return static_cast(mFlags | rhs.mFlags); } + Flags& operator|=(Flags rhs) { + mFlags = mFlags | rhs.mFlags; + return *this; + } + + Flags operator&(Flags rhs) const { return static_cast(mFlags & rhs.mFlags); } + Flags& operator&=(Flags rhs) { + mFlags = mFlags & rhs.mFlags; + return *this; + } + + Flags operator^(Flags rhs) const { return static_cast(mFlags ^ rhs.mFlags); } + Flags& operator^=(Flags rhs) { + mFlags = mFlags ^ rhs.mFlags; + return *this; + } + + Flags operator~() { return static_cast(~mFlags); } + + bool operator==(Flags rhs) const { return mFlags == rhs.mFlags; } + bool operator!=(Flags rhs) const { return !operator==(rhs); } + + Flags& operator=(const Flags& rhs) { + mFlags = rhs.mFlags; + return *this; + } + + inline Flags& clear(Flags f = static_cast(~static_cast(0))) { + return *this &= ~f; + } + + Iterator begin() const { return Iterator(*this); } + + Iterator end() const { return Iterator(); } + + /* + * Returns the stored set of flags. + * + * Note that this returns the underlying type rather than the base enum class. This is because + * the value is no longer necessarily a strict member of the enum since the returned value could + * be multiple enum variants OR'd together. + */ + U get() const { return mFlags; } + + std::string string() const { + std::string result; + bool first = true; + U unstringified = 0; + for (const F f : *this) { + if (const auto flagName = flag_name(f)) { + appendFlag(result, flagName.value(), first); + } else { + unstringified |= static_cast(f); + } + } + + if (unstringified != 0) { + constexpr auto radix = sizeof(U) == 1 ? Radix::kBin : Radix::kHex; + appendFlag(result, to_string(unstringified, radix), first); + } + + if (first) { + result += "0x0"; + } + + return result; + } + +private: + U mFlags; + + static void appendFlag(std::string& str, const std::string_view& flag, bool& first) { + if (first) { + first = false; + } else { + str += " | "; + } + str += flag; + } +}; + +// This namespace provides operator overloads for enum classes to make it easier to work with them +// as flags. In order to use these, add them via a `using namespace` declaration. +namespace flag_operators { + +template >> +inline Flags operator~(F f) { + return static_cast(~to_underlying(f)); +} + +template >> +Flags operator|(F lhs, F rhs) { + return static_cast(to_underlying(lhs) | to_underlying(rhs)); +} + +} // namespace flag_operators +} // namespace android::ftl diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index ef201965ad..c010a2e58a 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -14,11 +14,11 @@ cc_test { address: true, }, srcs: [ - "Flags_test.cpp", "cast_test.cpp", "concat_test.cpp", "enum_test.cpp", "fake_guard_test.cpp", + "flags_test.cpp", "future_test.cpp", "small_map_test.cpp", "small_vector_test.cpp", diff --git a/libs/ftl/Flags_test.cpp b/libs/ftl/Flags_test.cpp deleted file mode 100644 index d241fa272a..0000000000 --- a/libs/ftl/Flags_test.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include - -namespace android::test { - -using namespace android::flag_operators; - -enum class TestFlags : uint8_t { ONE = 0x1, TWO = 0x2, THREE = 0x4 }; - -TEST(Flags, Test) { - Flags flags = TestFlags::ONE; - ASSERT_TRUE(flags.test(TestFlags::ONE)); - ASSERT_FALSE(flags.test(TestFlags::TWO)); - ASSERT_FALSE(flags.test(TestFlags::THREE)); -} - -TEST(Flags, Any) { - Flags flags = TestFlags::ONE | TestFlags::TWO; - ASSERT_TRUE(flags.any(TestFlags::ONE)); - ASSERT_TRUE(flags.any(TestFlags::TWO)); - ASSERT_FALSE(flags.any(TestFlags::THREE)); - ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO)); - ASSERT_TRUE(flags.any(TestFlags::TWO | TestFlags::THREE)); - ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::THREE)); - ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); -} - -TEST(Flags, All) { - Flags flags = TestFlags::ONE | TestFlags::TWO; - ASSERT_TRUE(flags.all(TestFlags::ONE)); - ASSERT_TRUE(flags.all(TestFlags::TWO)); - ASSERT_FALSE(flags.all(TestFlags::THREE)); - ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO)); - ASSERT_FALSE(flags.all(TestFlags::TWO | TestFlags::THREE)); - ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::THREE)); - ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); -} - -TEST(Flags, DefaultConstructor_hasNoFlagsSet) { - Flags flags; - ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); -} - -TEST(Flags, NotOperator_onEmptyFlagsSetsAllFlags) { - Flags flags; - flags = ~flags; - ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); -} - -TEST(Flags, NotOperator_onNonEmptyFlagsInvertsFlags) { - Flags flags = TestFlags::TWO; - flags = ~flags; - ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE)); - ASSERT_FALSE(flags.test(TestFlags::TWO)); -} - -TEST(Flags, OrOperator_withNewFlag) { - Flags flags = TestFlags::ONE; - Flags flags2 = flags | TestFlags::TWO; - ASSERT_FALSE(flags2.test(TestFlags::THREE)); - ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::TWO)); -} - -TEST(Flags, OrOperator_withExistingFlag) { - Flags flags = TestFlags::ONE | TestFlags::THREE; - Flags flags2 = flags | TestFlags::THREE; - ASSERT_FALSE(flags2.test(TestFlags::TWO)); - ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::THREE)); -} - -TEST(Flags, OrEqualsOperator_withNewFlag) { - Flags flags; - flags |= TestFlags::THREE; - ASSERT_TRUE(flags.test(TestFlags::THREE)); - ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO)); -} - -TEST(Flags, OrEqualsOperator_withExistingFlag) { - Flags flags = TestFlags::ONE | TestFlags::THREE; - flags |= TestFlags::THREE; - ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE)); - ASSERT_FALSE(flags.test(TestFlags::TWO)); -} - -TEST(Flags, AndOperator_withOneSetFlag) { - Flags flags = TestFlags::ONE | TestFlags::THREE; - Flags andFlags = flags & TestFlags::THREE; - ASSERT_TRUE(andFlags.test(TestFlags::THREE)); - ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO)); -} - -TEST(Flags, AndOperator_withMultipleSetFlags) { - Flags flags = TestFlags::ONE | TestFlags::THREE; - Flags andFlags = flags & (TestFlags::ONE | TestFlags::THREE); - ASSERT_TRUE(andFlags.all(TestFlags::ONE | TestFlags::THREE)); - ASSERT_FALSE(andFlags.test(TestFlags::TWO)); -} - -TEST(Flags, AndOperator_withNoSetFlags) { - Flags flags = TestFlags::ONE | TestFlags::THREE; - Flags andFlags = flags & TestFlags::TWO; - ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); -} - -TEST(Flags, Equality) { - Flags flags1 = TestFlags::ONE | TestFlags::TWO; - Flags flags2 = TestFlags::ONE | TestFlags::TWO; - ASSERT_EQ(flags1, flags2); -} - -TEST(Flags, Inequality) { - Flags flags1 = TestFlags::ONE | TestFlags::TWO; - Flags flags2 = TestFlags::ONE | TestFlags::THREE; - ASSERT_NE(flags1, flags2); -} - -TEST(Flags, EqualsOperator) { - Flags flags; - flags = TestFlags::ONE; - ASSERT_TRUE(flags.test(TestFlags::ONE)); - ASSERT_FALSE(flags.any(TestFlags::TWO | TestFlags::THREE)); -} - -TEST(Flags, EqualsOperator_DontShareState) { - Flags flags1 = TestFlags::ONE | TestFlags::TWO; - Flags flags2 = flags1; - ASSERT_EQ(flags1, flags2); - - flags1 &= TestFlags::TWO; - ASSERT_NE(flags1, flags2); -} - -TEST(Flags, GetValue) { - Flags flags = TestFlags::ONE | TestFlags::TWO; - ASSERT_EQ(flags.get(), 0x3); -} - -TEST(Flags, String_NoFlags) { - Flags flags; - ASSERT_EQ(flags.string(), "0x0"); -} - -TEST(Flags, String_KnownValues) { - Flags flags = TestFlags::ONE | TestFlags::TWO; - ASSERT_EQ(flags.string(), "ONE | TWO"); -} - -TEST(Flags, String_UnknownValues) { - auto flags = Flags(0b1011); - ASSERT_EQ(flags.string(), "ONE | TWO | 0b1000"); -} - -TEST(FlagsIterator, IteratesOverAllFlags) { - Flags flags1 = TestFlags::ONE | TestFlags::TWO; - Flags flags2; - for (TestFlags f : flags1) { - flags2 |= f; - } - ASSERT_EQ(flags2, flags1); -} - -TEST(FlagsIterator, IteratesInExpectedOrder) { - const std::vector flagOrder = {TestFlags::ONE, TestFlags::TWO}; - Flags flags; - for (TestFlags f : flagOrder) { - flags |= f; - } - - size_t idx = 0; - auto iter = flags.begin(); - while (iter != flags.end() && idx < flagOrder.size()) { - // Make sure the order is what we expect - ASSERT_EQ(*iter, flagOrder[idx]); - iter++; - idx++; - } - ASSERT_EQ(iter, flags.end()); -} -TEST(FlagsIterator, PostFixIncrement) { - Flags flags = TestFlags::ONE | TestFlags::TWO; - auto iter = flags.begin(); - ASSERT_EQ(*(iter++), TestFlags::ONE); - ASSERT_EQ(*iter, TestFlags::TWO); - ASSERT_EQ(*(iter++), TestFlags::TWO); - ASSERT_EQ(iter, flags.end()); -} - -TEST(FlagsIterator, PreFixIncrement) { - Flags flags = TestFlags::ONE | TestFlags::TWO; - auto iter = flags.begin(); - ASSERT_EQ(*++iter, TestFlags::TWO); - ASSERT_EQ(++iter, flags.end()); -} - -} // namespace android::test diff --git a/libs/ftl/flags_test.cpp b/libs/ftl/flags_test.cpp new file mode 100644 index 0000000000..eea052ba33 --- /dev/null +++ b/libs/ftl/flags_test.cpp @@ -0,0 +1,214 @@ +/* + * 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 + +namespace android::test { + +using ftl::Flags; +using namespace ftl::flag_operators; + +enum class TestFlags : uint8_t { ONE = 0x1, TWO = 0x2, THREE = 0x4 }; + +TEST(Flags, Test) { + Flags flags = TestFlags::ONE; + ASSERT_TRUE(flags.test(TestFlags::ONE)); + ASSERT_FALSE(flags.test(TestFlags::TWO)); + ASSERT_FALSE(flags.test(TestFlags::THREE)); +} + +TEST(Flags, Any) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_TRUE(flags.any(TestFlags::ONE)); + ASSERT_TRUE(flags.any(TestFlags::TWO)); + ASSERT_FALSE(flags.any(TestFlags::THREE)); + ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO)); + ASSERT_TRUE(flags.any(TestFlags::TWO | TestFlags::THREE)); + ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::THREE)); + ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, All) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_TRUE(flags.all(TestFlags::ONE)); + ASSERT_TRUE(flags.all(TestFlags::TWO)); + ASSERT_FALSE(flags.all(TestFlags::THREE)); + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO)); + ASSERT_FALSE(flags.all(TestFlags::TWO | TestFlags::THREE)); + ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, DefaultConstructor_hasNoFlagsSet) { + Flags flags; + ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, NotOperator_onEmptyFlagsSetsAllFlags) { + Flags flags; + flags = ~flags; + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, NotOperator_onNonEmptyFlagsInvertsFlags) { + Flags flags = TestFlags::TWO; + flags = ~flags; + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(flags.test(TestFlags::TWO)); +} + +TEST(Flags, OrOperator_withNewFlag) { + Flags flags = TestFlags::ONE; + Flags flags2 = flags | TestFlags::TWO; + ASSERT_FALSE(flags2.test(TestFlags::THREE)); + ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::TWO)); +} + +TEST(Flags, OrOperator_withExistingFlag) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags flags2 = flags | TestFlags::THREE; + ASSERT_FALSE(flags2.test(TestFlags::TWO)); + ASSERT_TRUE(flags2.all(TestFlags::ONE | TestFlags::THREE)); +} + +TEST(Flags, OrEqualsOperator_withNewFlag) { + Flags flags; + flags |= TestFlags::THREE; + ASSERT_TRUE(flags.test(TestFlags::THREE)); + ASSERT_FALSE(flags.any(TestFlags::ONE | TestFlags::TWO)); +} + +TEST(Flags, OrEqualsOperator_withExistingFlag) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + flags |= TestFlags::THREE; + ASSERT_TRUE(flags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(flags.test(TestFlags::TWO)); +} + +TEST(Flags, AndOperator_withOneSetFlag) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags andFlags = flags & TestFlags::THREE; + ASSERT_TRUE(andFlags.test(TestFlags::THREE)); + ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO)); +} + +TEST(Flags, AndOperator_withMultipleSetFlags) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags andFlags = flags & (TestFlags::ONE | TestFlags::THREE); + ASSERT_TRUE(andFlags.all(TestFlags::ONE | TestFlags::THREE)); + ASSERT_FALSE(andFlags.test(TestFlags::TWO)); +} + +TEST(Flags, AndOperator_withNoSetFlags) { + Flags flags = TestFlags::ONE | TestFlags::THREE; + Flags andFlags = flags & TestFlags::TWO; + ASSERT_FALSE(andFlags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, Equality) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2 = TestFlags::ONE | TestFlags::TWO; + ASSERT_EQ(flags1, flags2); +} + +TEST(Flags, Inequality) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2 = TestFlags::ONE | TestFlags::THREE; + ASSERT_NE(flags1, flags2); +} + +TEST(Flags, EqualsOperator) { + Flags flags; + flags = TestFlags::ONE; + ASSERT_TRUE(flags.test(TestFlags::ONE)); + ASSERT_FALSE(flags.any(TestFlags::TWO | TestFlags::THREE)); +} + +TEST(Flags, EqualsOperator_DontShareState) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2 = flags1; + ASSERT_EQ(flags1, flags2); + + flags1 &= TestFlags::TWO; + ASSERT_NE(flags1, flags2); +} + +TEST(Flags, GetValue) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_EQ(flags.get(), 0x3); +} + +TEST(Flags, String_NoFlags) { + Flags flags; + ASSERT_EQ(flags.string(), "0x0"); +} + +TEST(Flags, String_KnownValues) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + ASSERT_EQ(flags.string(), "ONE | TWO"); +} + +TEST(Flags, String_UnknownValues) { + auto flags = Flags(0b1011); + ASSERT_EQ(flags.string(), "ONE | TWO | 0b1000"); +} + +TEST(FlagsIterator, IteratesOverAllFlags) { + Flags flags1 = TestFlags::ONE | TestFlags::TWO; + Flags flags2; + for (TestFlags f : flags1) { + flags2 |= f; + } + ASSERT_EQ(flags2, flags1); +} + +TEST(FlagsIterator, IteratesInExpectedOrder) { + const std::vector flagOrder = {TestFlags::ONE, TestFlags::TWO}; + Flags flags; + for (TestFlags f : flagOrder) { + flags |= f; + } + + size_t idx = 0; + auto iter = flags.begin(); + while (iter != flags.end() && idx < flagOrder.size()) { + // Make sure the order is what we expect + ASSERT_EQ(*iter, flagOrder[idx]); + iter++; + idx++; + } + ASSERT_EQ(iter, flags.end()); +} +TEST(FlagsIterator, PostFixIncrement) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + auto iter = flags.begin(); + ASSERT_EQ(*(iter++), TestFlags::ONE); + ASSERT_EQ(*iter, TestFlags::TWO); + ASSERT_EQ(*(iter++), TestFlags::TWO); + ASSERT_EQ(iter, flags.end()); +} + +TEST(FlagsIterator, PreFixIncrement) { + Flags flags = TestFlags::ONE | TestFlags::TWO; + auto iter = flags.begin(); + ASSERT_EQ(*++iter, TestFlags::TWO); + ASSERT_EQ(++iter, flags.end()); +} + +} // namespace android::test diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 34db5b1626..53c7f5ac14 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -815,7 +815,7 @@ status_t BufferData::writeToParcel(Parcel* output) const { status_t BufferData::readFromParcel(const Parcel* input) { int32_t tmpInt32; SAFE_PARCEL(input->readInt32, &tmpInt32); - flags = Flags(tmpInt32); + flags = ftl::Flags(tmpInt32); bool tmpBool = false; SAFE_PARCEL(input->readBool, &tmpBool); diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 2312a8cf0d..804ce4fac0 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -14,10 +14,11 @@ * limitations under the License. */ -#include #define LOG_TAG "WindowInfo" #define LOG_NDEBUG 0 +#include + #include #include @@ -25,8 +26,7 @@ namespace android::gui { -// --- WindowInfo --- -void WindowInfo::setInputConfig(Flags config, bool value) { +void WindowInfo::setInputConfig(ftl::Flags config, bool value) { if (value) { inputConfig |= config; return; @@ -182,18 +182,16 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { return status; } - layoutParamsFlags = Flags(lpFlags); + layoutParamsFlags = ftl::Flags(lpFlags); layoutParamsType = static_cast(lpType); transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); touchOcclusionMode = static_cast(touchOcclusionModeInt); - inputConfig = Flags(inputConfigInt); + inputConfig = ftl::Flags(inputConfigInt); touchableRegionCropHandle = touchableRegionCropHandleSp; return OK; } -// --- WindowInfoHandle --- - WindowInfoHandle::WindowInfoHandle() {} WindowInfoHandle::~WindowInfoHandle() {} diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 0a3cc19a13..b11e6748f0 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -126,7 +126,7 @@ public: frameRateOverride = 1 << 1, }; - using EventRegistrationFlags = Flags; + using EventRegistrationFlags = ftl::Flags; /* * Create a connection with SurfaceFlinger. diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 0f37dab53c..b33d4c0cc3 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -102,7 +103,7 @@ public: // was called with. sp releaseBufferEndpoint; - Flags flags; + ftl::Flags flags; client_cache_t cachedBuffer; diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index ef0b98b5cb..0e1d25812e 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -224,7 +224,7 @@ struct WindowInfo : public Parcelable { int32_t ownerPid = -1; int32_t ownerUid = -1; std::string packageName; - Flags inputConfig; + ftl::Flags inputConfig; int32_t displayId = ADISPLAY_ID_NONE; InputApplicationInfo applicationInfo; bool replaceTouchableRegionWithCrop = false; @@ -232,9 +232,9 @@ struct WindowInfo : public Parcelable { // The window's layout params flags and type set by WM. Type layoutParamsType = Type::UNKNOWN; - Flags layoutParamsFlags; + ftl::Flags layoutParamsFlags; - void setInputConfig(Flags config, bool value); + void setInputConfig(ftl::Flags config, bool value); void addTouchableRegion(const Rect& region); diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 8bd3899469..d6a6bd214e 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -60,10 +60,11 @@ #define INDENT3 " " using android::base::StringPrintf; -using namespace android::flag_operators; namespace android { +using namespace ftl::flag_operators; + static const char* DEVICE_INPUT_PATH = "/dev/input"; // v4l2 devices go directly into /dev static const char* DEVICE_PATH = "/dev"; @@ -302,7 +303,8 @@ static std::optional> getColorIndexArray( // --- Global Functions --- -Flags getAbsAxisUsage(int32_t axis, Flags deviceClasses) { +ftl::Flags getAbsAxisUsage(int32_t axis, + ftl::Flags deviceClasses) { // Touch devices get dibs on touch-related axes. if (deviceClasses.test(InputDeviceClass::TOUCH)) { switch (axis) { @@ -765,10 +767,10 @@ InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const { return device != nullptr ? device->identifier : InputDeviceIdentifier(); } -Flags EventHub::getDeviceClasses(int32_t deviceId) const { +ftl::Flags EventHub::getDeviceClasses(int32_t deviceId) const { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); - return device != nullptr ? device->classes : Flags(0); + return device != nullptr ? device->classes : ftl::Flags(0); } int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const { @@ -1909,7 +1911,7 @@ void EventHub::unregisterVideoDeviceFromEpollLocked(const TouchVideoDevice& vide } void EventHub::reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier, - Flags classes) { + ftl::Flags classes) { SHA256_CTX ctx; SHA256_Init(&ctx); SHA256_Update(&ctx, reinterpret_cast(identifier.uniqueId.c_str()), @@ -2191,7 +2193,7 @@ void EventHub::openDeviceLocked(const std::string& devicePath) { } // If the device isn't recognized as something we handle, don't monitor it. - if (device->classes == Flags(0)) { + if (device->classes == ftl::Flags(0)) { ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath.c_str(), device->identifier.name.c_str()); return; diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index a050963fef..ba5083bec3 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -18,9 +18,10 @@ #include "InputDevice.h" -#include #include +#include + #include "CursorInputMapper.h" #include "ExternalStylusInputMapper.h" #include "InputReaderContext.h" @@ -145,7 +146,7 @@ void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) { return; } std::unique_ptr contextPtr(new InputDeviceContext(*this, eventHubId)); - Flags classes = contextPtr->getDeviceClasses(); + ftl::Flags classes = contextPtr->getDeviceClasses(); std::vector> mappers; // Check if we should skip population @@ -236,7 +237,7 @@ void InputDevice::removeEventHubDevice(int32_t eventHubId) { void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { mSources = 0; - mClasses = Flags(0); + mClasses = ftl::Flags(0); mControllerNumber = 0; for_each_subdevice([this](InputDeviceContext& context) { diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 18e912db75..130c55639b 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -19,13 +19,12 @@ #include #include +#include #include #include -#include -#include - #include +#include #include #include #include @@ -189,7 +188,7 @@ struct RawLightInfo { int32_t id; std::string name; std::optional maxBrightness; - Flags flags; + ftl::Flags flags; std::array rgbIndex; std::filesystem::path path; }; @@ -198,7 +197,7 @@ struct RawLightInfo { struct RawBatteryInfo { int32_t id; std::string name; - Flags flags; + ftl::Flags flags; std::filesystem::path path; }; @@ -206,7 +205,8 @@ struct RawBatteryInfo { * Gets the class that owns an axis, in cases where multiple classes might claim * the same axis for different purposes. */ -extern Flags getAbsAxisUsage(int32_t axis, Flags deviceClasses); +extern ftl::Flags getAbsAxisUsage(int32_t axis, + ftl::Flags deviceClasses); /* * Grand Central Station for events. @@ -239,7 +239,7 @@ public: FIRST_SYNTHETIC_EVENT = DEVICE_ADDED, }; - virtual Flags getDeviceClasses(int32_t deviceId) const = 0; + virtual ftl::Flags getDeviceClasses(int32_t deviceId) const = 0; virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0; @@ -436,7 +436,7 @@ class EventHub : public EventHubInterface { public: EventHub(); - Flags getDeviceClasses(int32_t deviceId) const override final; + ftl::Flags getDeviceClasses(int32_t deviceId) const override final; InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override final; @@ -559,7 +559,7 @@ private: std::unique_ptr videoDevice; - Flags classes; + ftl::Flags classes; BitArray keyBitmask; BitArray keyState; @@ -662,7 +662,7 @@ private: int32_t getNextControllerNumberLocked(const std::string& name) REQUIRES(mLock); void releaseControllerNumberLocked(int32_t num) REQUIRES(mLock); void reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier, - Flags classes) REQUIRES(mLock); + ftl::Flags classes) REQUIRES(mLock); const std::unordered_map& getBatteryInfoLocked(int32_t deviceId) const REQUIRES(mLock); @@ -725,6 +725,6 @@ private: bool mPendingINotify; }; -}; // namespace android +} // namespace android #endif // _RUNTIME_EVENT_HUB_H diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 694daa99ce..728020eadc 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -17,12 +17,12 @@ #ifndef _UI_INPUTREADER_INPUT_DEVICE_H #define _UI_INPUTREADER_INPUT_DEVICE_H -#include +#include #include #include #include -#include +#include #include #include #include @@ -53,7 +53,7 @@ public: inline int32_t getGeneration() const { return mGeneration; } inline const std::string getName() const { return mIdentifier.name; } inline const std::string getDescriptor() { return mIdentifier.descriptor; } - inline Flags getClasses() const { return mClasses; } + inline ftl::Flags getClasses() const { return mClasses; } inline uint32_t getSources() const { return mSources; } inline bool hasEventHubDevices() const { return !mDevices.empty(); } @@ -160,7 +160,7 @@ private: int32_t mControllerNumber; InputDeviceIdentifier mIdentifier; std::string mAlias; - Flags mClasses; + ftl::Flags mClasses; // map from eventHubId to device context and mappers using MapperVector = std::vector>; @@ -250,7 +250,7 @@ public: inline int32_t getId() { return mDeviceId; } inline int32_t getEventHubId() { return mId; } - inline Flags getDeviceClasses() const { + inline ftl::Flags getDeviceClasses() const { return mEventHub->getDeviceClasses(mId); } inline InputDeviceIdentifier getDeviceIdentifier() const { diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index bf587050c6..864128734b 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -39,10 +39,11 @@ using android::gui::WindowInfo; using android::gui::WindowInfoHandle; using android::os::InputEventInjectionResult; using android::os::InputEventInjectionSync; -using namespace android::flag_operators; namespace android::inputdispatcher { +using namespace ftl::flag_operators; + // An arbitrary time value. static const nsecs_t ARBITRARY_TIME = 1234; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 9f33d23af5..8ba501c275 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +#include +#include + #include #include #include @@ -34,18 +37,15 @@ #include #include #include -#include -#include -#include -#include #include "input/DisplayViewport.h" #include "input/Input.h" namespace android { +using namespace ftl::flag_operators; + using std::chrono_literals::operator""ms; -using namespace android::flag_operators; // Timeout for waiting for an expected event static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms; @@ -429,7 +429,7 @@ class FakeEventHub : public EventHubInterface { struct Device { InputDeviceIdentifier identifier; - Flags classes; + ftl::Flags classes; PropertyMap configuration; KeyedVector absoluteAxes; KeyedVector relativeAxes; @@ -457,7 +457,7 @@ class FakeEventHub : public EventHubInterface { return OK; } - explicit Device(Flags classes) : classes(classes), enabled(true) {} + explicit Device(ftl::Flags classes) : classes(classes), enabled(true) {} }; std::mutex mLock; @@ -484,7 +484,8 @@ public: FakeEventHub() { } - void addDevice(int32_t deviceId, const std::string& name, Flags classes) { + void addDevice(int32_t deviceId, const std::string& name, + ftl::Flags classes) { Device* device = new Device(classes); device->identifier.name = name; mDevices.add(deviceId, device); @@ -695,9 +696,9 @@ private: return index >= 0 ? mDevices.valueAt(index) : nullptr; } - Flags getDeviceClasses(int32_t deviceId) const override { + ftl::Flags getDeviceClasses(int32_t deviceId) const override { Device* device = getDevice(deviceId); - return device ? device->classes : Flags(0); + return device ? device->classes : ftl::Flags(0); } InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override { @@ -1572,8 +1573,8 @@ protected: mFakePolicy.clear(); } - void addDevice(int32_t eventHubId, const std::string& name, Flags classes, - const PropertyMap* configuration) { + void addDevice(int32_t eventHubId, const std::string& name, + ftl::Flags classes, const PropertyMap* configuration) { mFakeEventHub->addDevice(eventHubId, name, classes); if (configuration) { @@ -1598,7 +1599,8 @@ protected: FakeInputMapper& addDeviceWithFakeInputMapper(int32_t deviceId, int32_t eventHubId, const std::string& name, - Flags classes, uint32_t sources, + ftl::Flags classes, + uint32_t sources, const PropertyMap* configuration) { std::shared_ptr device = mReader->newDevice(deviceId, name); FakeInputMapper& mapper = device->addMapper(eventHubId, sources); @@ -1610,7 +1612,7 @@ protected: TEST_F(InputReaderTest, PolicyGetInputDevices) { ASSERT_NO_FATAL_FAILURE(addDevice(1, "keyboard", InputDeviceClass::KEYBOARD, nullptr)); - ASSERT_NO_FATAL_FAILURE(addDevice(2, "ignored", Flags(0), + ASSERT_NO_FATAL_FAILURE(addDevice(2, "ignored", ftl::Flags(0), nullptr)); // no classes so device will be ignored // Should also have received a notification describing the new input devices. @@ -1672,7 +1674,7 @@ TEST_F(InputReaderTest, GetMergedInputDevicesEnabled) { TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass(InputDeviceClass::KEYBOARD); + constexpr ftl::Flags deviceClass(InputDeviceClass::KEYBOARD); constexpr int32_t eventHubId = 1; std::shared_ptr device = mReader->newDevice(deviceId, "fake"); // Must add at least one mapper or the device will be ignored! @@ -1709,7 +1711,7 @@ TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) { TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; FakeInputMapper& mapper = addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass, @@ -1773,7 +1775,7 @@ TEST_F(InputReaderTest, GetKeyCodeForKeyLocation_NoKeyboardMapper) { TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; FakeInputMapper& mapper = addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass, @@ -1806,7 +1808,7 @@ TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; FakeInputMapper& mapper = addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass, @@ -1839,7 +1841,7 @@ TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; FakeInputMapper& mapper = addDeviceWithFakeInputMapper(deviceId, eventHubId, "fake", deviceClass, @@ -1891,7 +1893,7 @@ TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChange TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr nsecs_t when = 0; constexpr int32_t eventHubId = 1; constexpr nsecs_t readTime = 2; @@ -1915,7 +1917,7 @@ TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { TEST_F(InputReaderTest, DeviceReset_RandomId) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; std::shared_ptr device = mReader->newDevice(deviceId, "fake"); // Must add at least one mapper or the device will be ignored! @@ -1948,7 +1950,7 @@ TEST_F(InputReaderTest, DeviceReset_RandomId) { TEST_F(InputReaderTest, DeviceReset_GenerateIdWithInputReaderSource) { constexpr int32_t deviceId = 1; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; std::shared_ptr device = mReader->newDevice(deviceId, "fake"); // Must add at least one mapper or the device will be ignored! @@ -1963,7 +1965,7 @@ TEST_F(InputReaderTest, DeviceReset_GenerateIdWithInputReaderSource) { TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "USB1"; std::shared_ptr device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); @@ -2008,7 +2010,7 @@ TEST_F(InputReaderTest, Device_CanDispatchToDisplay) { TEST_F(InputReaderTest, WhenEnabledChanges_AllSubdevicesAreUpdated) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1}; std::shared_ptr device = mReader->newDevice(deviceId, "fake"); // Must add at least one mapper or the device will be ignored! @@ -2049,7 +2051,7 @@ TEST_F(InputReaderTest, WhenEnabledChanges_AllSubdevicesAreUpdated) { TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToSubdeviceMappers) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - constexpr Flags deviceClass = InputDeviceClass::KEYBOARD; + constexpr ftl::Flags deviceClass = InputDeviceClass::KEYBOARD; constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1}; // Add two subdevices to device std::shared_ptr device = mReader->newDevice(deviceId, "fake"); @@ -2106,7 +2108,8 @@ public: TEST_F(InputReaderTest, VibratorGetVibratorIds) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - Flags deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::VIBRATOR; + ftl::Flags deviceClass = + InputDeviceClass::KEYBOARD | InputDeviceClass::VIBRATOR; constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "BLUETOOTH"; std::shared_ptr device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); @@ -2166,7 +2169,8 @@ private: TEST_F(InputReaderTest, BatteryGetCapacity) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - Flags deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY; + ftl::Flags deviceClass = + InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY; constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "BLUETOOTH"; std::shared_ptr device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); @@ -2182,7 +2186,8 @@ TEST_F(InputReaderTest, BatteryGetCapacity) { TEST_F(InputReaderTest, BatteryGetStatus) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - Flags deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY; + ftl::Flags deviceClass = + InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY; constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "BLUETOOTH"; std::shared_ptr device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); @@ -2198,7 +2203,7 @@ TEST_F(InputReaderTest, BatteryGetStatus) { TEST_F(InputReaderTest, LightGetColor) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; - Flags deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT; + ftl::Flags deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT; constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "BLUETOOTH"; std::shared_ptr device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); @@ -2625,7 +2630,7 @@ protected: static const int32_t DEVICE_ID; static const int32_t DEVICE_GENERATION; static const int32_t DEVICE_CONTROLLER_NUMBER; - static const Flags DEVICE_CLASSES; + static const ftl::Flags DEVICE_CLASSES; static const int32_t EVENTHUB_ID; std::shared_ptr mFakeEventHub; @@ -2646,7 +2651,7 @@ protected: mDevice = std::make_shared(mReader->getContext(), DEVICE_ID, DEVICE_GENERATION, identifier); mReader->pushNextDevice(mDevice); - mFakeEventHub->addDevice(EVENTHUB_ID, DEVICE_NAME, Flags(0)); + mFakeEventHub->addDevice(EVENTHUB_ID, DEVICE_NAME, ftl::Flags(0)); mReader->loopOnce(); } @@ -2661,14 +2666,14 @@ const char* InputDeviceTest::DEVICE_LOCATION = "USB1"; const int32_t InputDeviceTest::DEVICE_ID = END_RESERVED_ID + 1000; const int32_t InputDeviceTest::DEVICE_GENERATION = 2; const int32_t InputDeviceTest::DEVICE_CONTROLLER_NUMBER = 0; -const Flags InputDeviceTest::DEVICE_CLASSES = +const ftl::Flags InputDeviceTest::DEVICE_CLASSES = InputDeviceClass::KEYBOARD | InputDeviceClass::TOUCH | InputDeviceClass::JOYSTICK; const int32_t InputDeviceTest::EVENTHUB_ID = 1; TEST_F(InputDeviceTest, ImmutableProperties) { ASSERT_EQ(DEVICE_ID, mDevice->getId()); ASSERT_STREQ(DEVICE_NAME, mDevice->getName().c_str()); - ASSERT_EQ(Flags(0), mDevice->getClasses()); + ASSERT_EQ(ftl::Flags(0), mDevice->getClasses()); } TEST_F(InputDeviceTest, WhenDeviceCreated_EnabledIsFalse) { @@ -2912,7 +2917,7 @@ protected: static const int32_t DEVICE_ID; static const int32_t DEVICE_GENERATION; static const int32_t DEVICE_CONTROLLER_NUMBER; - static const Flags DEVICE_CLASSES; + static const ftl::Flags DEVICE_CLASSES; static const int32_t EVENTHUB_ID; std::shared_ptr mFakeEventHub; @@ -2921,7 +2926,7 @@ protected: std::unique_ptr mReader; std::shared_ptr mDevice; - virtual void SetUp(Flags classes) { + virtual void SetUp(ftl::Flags classes) { mFakeEventHub = std::make_unique(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = std::make_unique(); @@ -2953,7 +2958,7 @@ protected: std::shared_ptr newDevice(int32_t deviceId, const std::string& name, const std::string& location, int32_t eventHubId, - Flags classes) { + ftl::Flags classes) { InputDeviceIdentifier identifier; identifier.name = name; identifier.location = location; @@ -3045,8 +3050,8 @@ const char* InputMapperTest::DEVICE_LOCATION = "USB1"; const int32_t InputMapperTest::DEVICE_ID = END_RESERVED_ID + 1000; const int32_t InputMapperTest::DEVICE_GENERATION = 2; const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0; -const Flags InputMapperTest::DEVICE_CLASSES = - Flags(0); // not needed for current tests +const ftl::Flags InputMapperTest::DEVICE_CLASSES = + ftl::Flags(0); // not needed for current tests const int32_t InputMapperTest::EVENTHUB_ID = 1; // --- SwitchInputMapperTest --- @@ -3842,7 +3847,7 @@ TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) { constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1; std::shared_ptr device2 = newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID, - Flags(0)); + ftl::Flags(0)); mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); @@ -3954,7 +3959,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleAfterReattach) { constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1; std::shared_ptr device2 = newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID, - Flags(0)); + ftl::Flags(0)); mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_CAPSL, true /*initially on*/); mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_NUML, false /*initially off*/); mFakeEventHub->addLed(SECOND_EVENTHUB_ID, LED_SCROLLL, false /*initially off*/); @@ -8409,7 +8414,7 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) { constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1; std::shared_ptr device2 = newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID, - Flags(0)); + ftl::Flags(0)); mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0 /*flat*/, 0 /*fuzz*/); @@ -9350,7 +9355,7 @@ protected: static const int32_t DEVICE_ID; static const int32_t DEVICE_GENERATION; static const int32_t DEVICE_CONTROLLER_NUMBER; - static const Flags DEVICE_CLASSES; + static const ftl::Flags DEVICE_CLASSES; static const int32_t EVENTHUB_ID; std::shared_ptr mFakeEventHub; @@ -9359,7 +9364,7 @@ protected: std::unique_ptr mReader; std::shared_ptr mDevice; - virtual void SetUp(Flags classes) { + virtual void SetUp(ftl::Flags classes) { mFakeEventHub = std::make_unique(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = std::make_unique(); @@ -9385,7 +9390,7 @@ protected: std::shared_ptr newDevice(int32_t deviceId, const std::string& name, const std::string& location, int32_t eventHubId, - Flags classes) { + ftl::Flags classes) { InputDeviceIdentifier identifier; identifier.name = name; identifier.location = location; @@ -9411,8 +9416,8 @@ const char* PeripheralControllerTest::DEVICE_LOCATION = "BLUETOOTH"; const int32_t PeripheralControllerTest::DEVICE_ID = END_RESERVED_ID + 1000; const int32_t PeripheralControllerTest::DEVICE_GENERATION = 2; const int32_t PeripheralControllerTest::DEVICE_CONTROLLER_NUMBER = 0; -const Flags PeripheralControllerTest::DEVICE_CLASSES = - Flags(0); // not needed for current tests +const ftl::Flags PeripheralControllerTest::DEVICE_CLASSES = + ftl::Flags(0); // not needed for current tests const int32_t PeripheralControllerTest::EVENTHUB_ID = 1; // --- BatteryControllerTest --- diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h index cb00e719f8..29d33662ab 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h @@ -16,20 +16,20 @@ #pragma once +#include + +#include +#include #include +#include +#include + #include #include #include #include -#include - -#include #include "DisplayHardware/Hal.h" -#include "math/HashCombine.h" - -#include -#include namespace std { template @@ -84,13 +84,13 @@ class StateInterface { public: virtual ~StateInterface() = default; - virtual Flags update(const compositionengine::OutputLayer* layer) = 0; + virtual ftl::Flags update(const compositionengine::OutputLayer* layer) = 0; virtual size_t getHash() const = 0; virtual LayerStateField getField() const = 0; - virtual Flags getFieldIfDifferent(const StateInterface* other) const = 0; + virtual ftl::Flags getFieldIfDifferent(const StateInterface* other) const = 0; virtual bool equals(const StateInterface* other) const = 0; @@ -152,12 +152,12 @@ public: ~OutputLayerState() override = default; // Returns this member's field flag if it was changed - Flags update(const compositionengine::OutputLayer* layer) override { + ftl::Flags update(const compositionengine::OutputLayer* layer) override { T newValue = mReader(layer); return update(newValue); } - Flags update(const T& newValue) { + ftl::Flags update(const T& newValue) { if (!mEquals(mValue, newValue)) { mValue = newValue; mHash = {}; @@ -176,14 +176,14 @@ public: return *mHash; } - Flags getFieldIfDifferent(const StateInterface* other) const override { + ftl::Flags getFieldIfDifferent(const StateInterface* other) const override { if (other->getField() != FIELD) { return {}; } // The early return ensures that this downcast is sound const OutputLayerState* otherState = static_cast(other); - return *this != *otherState ? FIELD : Flags{}; + return *this != *otherState ? FIELD : ftl::Flags{}; } bool equals(const StateInterface* other) const override { @@ -215,7 +215,7 @@ public: LayerState(compositionengine::OutputLayer* layer); // Returns which fields were updated - Flags update(compositionengine::OutputLayer*); + ftl::Flags update(compositionengine::OutputLayer*); // Computes a hash for this LayerState. // The hash is only computed from NonUniqueFields, and excludes GraphicBuffers since they are @@ -224,7 +224,7 @@ public: // Returns the bit-set of differing fields between this LayerState and another LayerState. // This bit-set is based on NonUniqueFields only, and excludes GraphicBuffers. - Flags getDifferingFields(const LayerState& other) const; + ftl::Flags getDifferingFields(const LayerState& other) const; compositionengine::OutputLayer* getOutputLayer() const { return mOutputLayer; } int32_t getId() const { return mId.get(); } diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h index ef1560e23d..6be673597e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h @@ -16,6 +16,8 @@ #pragma once +#include + #include namespace android::compositionengine::impl::planner { @@ -35,7 +37,7 @@ public: // This implies that only one layer is allowed to differ in an approximate match. size_t differingIndex; // Set of fields that differ for the differing layer in the approximate match. - Flags differingFields; + ftl::Flags differingFields; }; // Returns an approximate match when comparing this layer stack with the provided list of diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp index c79ca0d959..f439caf9e1 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp @@ -41,7 +41,7 @@ LayerState::LayerState(compositionengine::OutputLayer* layer) update(layer); } -Flags LayerState::update(compositionengine::OutputLayer* layer) { +ftl::Flags LayerState::update(compositionengine::OutputLayer* layer) { ALOGE_IF(mOutputLayer != layer && layer->getLayerFE().getSequence() != mId.get(), "[%s] Expected mOutputLayer ID to never change: %d, %d", __func__, layer->getLayerFE().getSequence(), mId.get()); @@ -50,7 +50,7 @@ Flags LayerState::update(compositionengine::OutputLayer* layer) // same, i.e., the LayerFE is the same. An example use-case is screen rotation. mOutputLayer = layer; - Flags differences; + ftl::Flags differences; // Update the unique fields as well, since we have to set them at least // once from the OutputLayer @@ -76,8 +76,8 @@ size_t LayerState::getHash() const { return hash; } -Flags LayerState::getDifferingFields(const LayerState& other) const { - Flags differences; +ftl::Flags LayerState::getDifferingFields(const LayerState& other) const { + ftl::Flags differences; auto myFields = getNonUniqueFields(); auto otherFields = other.getNonUniqueFields(); for (size_t i = 0; i < myFields.size(); ++i) { diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp index 74d27015d7..c8413eb8bc 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp @@ -97,7 +97,7 @@ void Planner::plan( if (const auto layerEntry = mPreviousLayers.find(id); layerEntry != mPreviousLayers.end()) { // Track changes from previous info LayerState& state = layerEntry->second; - Flags differences = state.update(layer); + ftl::Flags differences = state.update(layer); if (differences.get() == 0) { state.incrementFramesSinceBufferUpdate(); } else { diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp index 2d53583ed8..2fc029fdc6 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp @@ -57,7 +57,7 @@ std::optional LayerStack::getApproximateMatch( return std::nullopt; } - Flags differingFields = mLayers[i].getDifferingFields(*other[i]); + ftl::Flags differingFields = mLayers[i].getDifferingFields(*other[i]); // If we don't find an approximate match on this layer, then the LayerStacks differ // by too much, so return nothing diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp index bd4ff13236..5c6e8da58c 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp @@ -97,12 +97,12 @@ struct LayerStateTest : public testing::Test { void verifyUniqueDifferingFields(const LayerState& lhs, const LayerState& rhs) { EXPECT_EQ(lhs.getHash(), rhs.getHash()); - EXPECT_EQ(Flags(LayerStateField::None), lhs.getDifferingFields(rhs)); - EXPECT_EQ(Flags(LayerStateField::None), rhs.getDifferingFields(lhs)); + EXPECT_EQ(ftl::Flags(LayerStateField::None), lhs.getDifferingFields(rhs)); + EXPECT_EQ(ftl::Flags(LayerStateField::None), rhs.getDifferingFields(lhs)); } void verifyNonUniqueDifferingFields(const LayerState& lhs, const LayerState& rhs, - Flags fields) { + ftl::Flags fields) { EXPECT_NE(lhs.getHash(), rhs.getHash()); EXPECT_EQ(fields, lhs.getDifferingFields(rhs)); @@ -159,9 +159,9 @@ TEST_F(LayerStateTest, updateId) { sp newLayerFE = sp::make(); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionState, sSequenceIdTwo); - Flags updates = mLayerState->update(&newOutputLayer); + ftl::Flags updates = mLayerState->update(&newOutputLayer); EXPECT_EQ(sSequenceIdTwo, mLayerState->getId()); - EXPECT_EQ(Flags(LayerStateField::Id), updates); + EXPECT_EQ(ftl::Flags(LayerStateField::Id), updates); } TEST_F(LayerStateTest, compareId) { @@ -204,9 +204,9 @@ TEST_F(LayerStateTest, updateName) { sp newLayerFE = sp::make(); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionState, sSequenceId, sDebugNameTwo); - Flags updates = mLayerState->update(&newOutputLayer); + ftl::Flags updates = mLayerState->update(&newOutputLayer); EXPECT_EQ(sDebugNameTwo, mLayerState->getName()); - EXPECT_EQ(Flags(LayerStateField::Name), updates); + EXPECT_EQ(ftl::Flags(LayerStateField::Name), updates); } TEST_F(LayerStateTest, compareName) { @@ -253,9 +253,9 @@ TEST_F(LayerStateTest, updateDisplayFrame) { outputLayerCompositionStateTwo.displayFrame = sRectTwo; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo, layerFECompositionState); - Flags updates = mLayerState->update(&newOutputLayer); + ftl::Flags updates = mLayerState->update(&newOutputLayer); EXPECT_EQ(sRectTwo, mLayerState->getDisplayFrame()); - EXPECT_EQ(Flags(LayerStateField::DisplayFrame), updates); + EXPECT_EQ(ftl::Flags(LayerStateField::DisplayFrame), updates); } TEST_F(LayerStateTest, compareDisplayFrame) { @@ -315,9 +315,9 @@ TEST_F(LayerStateTest, updateCompositionType) { layerFECompositionStateTwo.compositionType = Composition::SOLID_COLOR; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); + ftl::Flags updates = mLayerState->update(&newOutputLayer); EXPECT_EQ(Composition::SOLID_COLOR, mLayerState->getCompositionType()); - EXPECT_EQ(Flags(LayerStateField::CompositionType), updates); + EXPECT_EQ(ftl::Flags(LayerStateField::CompositionType), updates); } TEST_F(LayerStateTest, compareCompositionType) { @@ -357,8 +357,8 @@ TEST_F(LayerStateTest, updateBuffer) { layerFECompositionStateTwo.buffer = new GraphicBuffer(); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::Buffer), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::Buffer), updates); } TEST_F(LayerStateTest, updateBufferSingleBufferedLegacy) { @@ -380,8 +380,8 @@ TEST_F(LayerStateTest, updateBufferSingleBufferedLegacy) { layerFECompositionStateTwo.frameNumber = i; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::Buffer), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::Buffer), updates); } } @@ -404,8 +404,8 @@ TEST_F(LayerStateTest, updateBufferSingleBufferedUsage) { for (uint64_t i = 0; i < 10; i++) { setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::Buffer), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::Buffer), updates); } } @@ -446,8 +446,8 @@ TEST_F(LayerStateTest, updateSourceCrop) { outputLayerCompositionStateTwo.sourceCrop = sFloatRectTwo; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo, layerFECompositionState); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::SourceCrop), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::SourceCrop), updates); } TEST_F(LayerStateTest, compareSourceCrop) { @@ -485,8 +485,8 @@ TEST_F(LayerStateTest, updateBufferTransform) { outputLayerCompositionStateTwo.bufferTransform = Hwc2::Transform::FLIP_V; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo, layerFECompositionState); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::BufferTransform), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::BufferTransform), updates); } TEST_F(LayerStateTest, compareBufferTransform) { @@ -525,8 +525,8 @@ TEST_F(LayerStateTest, updateBlendMode) { layerFECompositionStateTwo.blendMode = hal::BlendMode::PREMULTIPLIED; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::BlendMode), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::BlendMode), updates); } TEST_F(LayerStateTest, compareBlendMode) { @@ -564,8 +564,8 @@ TEST_F(LayerStateTest, updateAlpha) { layerFECompositionStateTwo.alpha = sAlphaTwo; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::Alpha), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::Alpha), updates); } TEST_F(LayerStateTest, compareAlpha) { @@ -603,8 +603,8 @@ TEST_F(LayerStateTest, updateLayerMetadata) { layerFECompositionStateTwo.metadata[sMetadataKeyTwo] = sMetadataValueTwo; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::LayerMetadata), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::LayerMetadata), updates); } TEST_F(LayerStateTest, compareLayerMetadata) { @@ -652,8 +652,8 @@ TEST_F(LayerStateTest, updateVisibleRegion) { outputLayerCompositionStateTwo.visibleRegion = sRegionTwo; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo, layerFECompositionState); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::VisibleRegion), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::VisibleRegion), updates); } TEST_F(LayerStateTest, compareVisibleRegion) { @@ -691,8 +691,8 @@ TEST_F(LayerStateTest, updateDataspace) { outputLayerCompositionStateTwo.dataspace = ui::Dataspace::DISPLAY_P3; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo, layerFECompositionState); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::Dataspace), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::Dataspace), updates); } TEST_F(LayerStateTest, compareDataspace) { @@ -738,9 +738,9 @@ TEST_F(LayerStateTest, updatePixelFormat) { "buffer2"); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::Buffer) | - Flags(LayerStateField::PixelFormat), + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::Buffer) | + ftl::Flags(LayerStateField::PixelFormat), updates); } @@ -768,7 +768,7 @@ TEST_F(LayerStateTest, comparePixelFormat) { auto otherLayerState = std::make_unique(&newOutputLayer); verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, - Flags(LayerStateField::PixelFormat)); + ftl::Flags(LayerStateField::PixelFormat)); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); @@ -790,8 +790,8 @@ TEST_F(LayerStateTest, updateColorTransform) { layerFECompositionStateTwo.colorTransform = sMat4One; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::ColorTransform), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::ColorTransform), updates); } TEST_F(LayerStateTest, compareColorTransform) { @@ -831,8 +831,8 @@ TEST_F(LayerStateTest, updateSidebandStream) { layerFECompositionStateTwo.sidebandStream = NativeHandle::create(sFakeSidebandStreamTwo, false); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::SidebandStream), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::SidebandStream), updates); } TEST_F(LayerStateTest, compareSidebandStream) { @@ -870,8 +870,8 @@ TEST_F(LayerStateTest, updateSolidColor) { layerFECompositionStateTwo.color = sHalf4Two; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::SolidColor), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::SolidColor), updates); } TEST_F(LayerStateTest, compareSolidColor) { @@ -909,8 +909,8 @@ TEST_F(LayerStateTest, updateBackgroundBlur) { layerFECompositionStateTwo.backgroundBlurRadius = sBgBlurRadiusTwo; setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::BackgroundBlurRadius), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::BackgroundBlurRadius), updates); } TEST_F(LayerStateTest, compareBackgroundBlur) { @@ -949,8 +949,8 @@ TEST_F(LayerStateTest, updateBlurRegions) { layerFECompositionStateTwo.blurRegions.push_back(sBlurRegionTwo); setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, layerFECompositionStateTwo); - Flags updates = mLayerState->update(&newOutputLayer); - EXPECT_EQ(Flags(LayerStateField::BlurRegions), updates); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::BlurRegions), updates); } TEST_F(LayerStateTest, compareBlurRegions) { diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index b4fb51f9d5..3803a78670 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -19,20 +19,20 @@ #pragma clang diagnostic ignored "-Wconversion" // #define LOG_NDEBUG 0 -#include "VirtualDisplaySurface.h" #include -#include "HWComposer.h" -#include "SurfaceFlinger.h" - -#include #include +#include #include #include #include #include +#include "HWComposer.h" +#include "SurfaceFlinger.h" +#include "VirtualDisplaySurface.h" + #define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \ mDisplayName.c_str(), ##__VA_ARGS__) #define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \ @@ -657,7 +657,7 @@ auto VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) -> std::string VirtualDisplaySurface::toString(CompositionType type) { using namespace std::literals; - return type == CompositionType::Unknown ? "Unknown"s : Flags(type).string(); + return type == CompositionType::Unknown ? "Unknown"s : ftl::Flags(type).string(); } } // namespace android diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 894fb8d47b..41e048715c 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -82,11 +82,13 @@ namespace { constexpr int kDumpTableRowLength = 159; } // namespace +using namespace ftl::flag_operators; + using base::StringAppendF; -using namespace android::flag_operators; -using PresentState = frametimeline::SurfaceFrame::PresentState; using gui::WindowInfo; +using PresentState = frametimeline::SurfaceFrame::PresentState; + std::atomic Layer::sSequence{1}; Layer::Layer(const LayerCreationArgs& args) diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Features.h b/services/surfaceflinger/Scheduler/include/scheduler/Features.h index 0e96678420..b3a6a606c3 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/Features.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/Features.h @@ -16,10 +16,10 @@ #pragma once -#include - #include +#include + namespace android::scheduler { enum class Feature : std::uint8_t { @@ -29,6 +29,6 @@ enum class Feature : std::uint8_t { kTracePredictedVsync = 0b1000, }; -using FeatureFlags = Flags; +using FeatureFlags = ftl::Flags; } // namespace android::scheduler diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index d249b60f2a..a73eccf0e5 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -429,7 +429,7 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta bufferProto.height(), bufferProto.pixel_format(), bufferProto.usage())); layer.bufferData->frameNumber = bufferProto.frame_number(); - layer.bufferData->flags = Flags(bufferProto.flags()); + layer.bufferData->flags = ftl::Flags(bufferProto.flags()); layer.bufferData->cachedBuffer.id = bufferProto.cached_buffer_id(); layer.bufferData->acquireFence = Fence::NO_FENCE; } diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 14d8f987b0..fa36d9c16b 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -34,12 +34,13 @@ using namespace std::chrono_literals; using namespace std::placeholders; -using namespace android::flag_operators; using testing::_; using testing::Invoke; namespace android { +using namespace ftl::flag_operators; + namespace { constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = PhysicalDisplayId::fromPort(111u); -- cgit v1.2.3-59-g8ed1b From 1f6fc70ab0c6efdaa1c60dd2ced32fb6833c92e2 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Mon, 21 Mar 2022 08:34:50 -0700 Subject: SF: Fix feedback loop with refresh rate overlay RefreshRateOverlay was refactored to use transactions instead of APIs internal to SF. A side effect is that the overlay layer feeds back into the frame rate detection and idle heuristics, which causes oscillation that trends to the high refresh rate. The transaction to setFrameRate failed to apply, as the NoVote argument was invalid. Make it valid, such that LayerHistory::summarize skips the overlay layer. Do not reset the idle timer for solely NO_VOTE transactions. Bug: 221081400 Test: flame is not stuck at 90 Hz when overlay is enabled. Test: Same with sf.debug.show_refresh_rate_overlay_spinner Test: SetFrameRateTest Change-Id: I6322c1c487672b602a0f974e8ecf445633dcc3a1 --- libs/gui/LayerState.cpp | 11 +++--- libs/nativewindow/include/apex/window.h | 13 ------- libs/nativewindow/include/system/window.h | 18 ++++++++++ services/surfaceflinger/Layer.cpp | 2 ++ services/surfaceflinger/RefreshRateOverlay.cpp | 42 ++++++++++------------ services/surfaceflinger/SurfaceFlinger.cpp | 19 ++++------ services/surfaceflinger/SurfaceFlinger.h | 3 +- services/surfaceflinger/TransactionState.h | 36 +++++++++++++++++-- .../tests/unittests/SetFrameRateTest.cpp | 21 +++++++---- 9 files changed, 101 insertions(+), 64 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index f7cd5c4f71..502031c8d8 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -16,8 +16,8 @@ #define LOG_TAG "LayerState" -#include -#include +#include +#include #include #include @@ -25,10 +25,9 @@ #include #include #include +#include #include -#include - namespace android { using gui::FocusRequest; @@ -679,7 +678,9 @@ bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrame if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT && compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE && - (!privileged || compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT)) { + (!privileged || + (compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT && + compatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE))) { ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName, compatibility, privileged ? "yes" : "no"); return false; diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h index 0923438eec..2d1354cdf1 100644 --- a/libs/nativewindow/include/apex/window.h +++ b/libs/nativewindow/include/apex/window.h @@ -39,19 +39,6 @@ enum ANativeWindowPerform { // clang-format on }; -/* - * Internal extension of compatibility value for ANativeWindow_setFrameRate. */ -enum ANativeWindow_FrameRateCompatibilityInternal { - /** - * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display - * to operate at the exact frame rate. - * - * This is used internally by the platform and should not be used by apps. - * @hide - */ - ANATIVEWINDOW_FRAME_RATE_EXACT = 100, -}; - /** * Prototype of the function that an ANativeWindow implementation would call * when ANativeWindow_cancelBuffer is called. diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index a319769148..a54af1fa62 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1018,6 +1018,24 @@ static inline int native_window_set_auto_prerotation(struct ANativeWindow* windo return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation); } +/* + * Internal extension of ANativeWindow_FrameRateCompatibility. + */ +enum { + /** + * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display + * to operate at the exact frame rate. + * + * Keep in sync with Surface.java constant. + */ + ANATIVEWINDOW_FRAME_RATE_EXACT = 100, + + /** + * This surface is ignored while choosing the refresh rate. + */ + ANATIVEWINDOW_FRAME_RATE_NO_VOTE, +}; + static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) { return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate, diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 997b1a1b1a..f7e1d1ee95 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2596,6 +2596,8 @@ Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t comp return FrameRateCompatibility::ExactOrMultiple; case ANATIVEWINDOW_FRAME_RATE_EXACT: return FrameRateCompatibility::Exact; + case ANATIVEWINDOW_FRAME_RATE_NO_VOTE: + return FrameRateCompatibility::NoVote; default: LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility); return FrameRateCompatibility::Default; diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 80aa07231f..d4435c2818 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -45,6 +45,15 @@ constexpr int kDigitSpace = 16; constexpr int kBufferWidth = 4 * kDigitWidth + 3 * kDigitSpace; constexpr int kBufferHeight = kDigitHeight; +SurfaceComposerClient::Transaction createTransaction(const sp& surface) { + constexpr float kFrameRate = 0.f; + constexpr int8_t kCompatibility = ANATIVEWINDOW_FRAME_RATE_NO_VOTE; + constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS; + + return SurfaceComposerClient::Transaction().setFrameRate(surface, kFrameRate, kCompatibility, + kSeamlessness); +} + } // namespace void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor color, @@ -213,12 +222,7 @@ RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, bool showSpinner) return; } - constexpr float kFrameRate = 0.f; - constexpr int8_t kCompatibility = static_cast(Layer::FrameRateCompatibility::NoVote); - constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS; - - SurfaceComposerClient::Transaction() - .setFrameRate(mSurfaceControl, kFrameRate, kCompatibility, kSeamlessness) + createTransaction(mSurfaceControl) .setLayer(mSurfaceControl, INT32_MAX - 2) .setTrustedOverlay(mSurfaceControl, true) .apply(); @@ -243,9 +247,7 @@ auto RefreshRateOverlay::getOrCreateBuffers(Fps fps) -> const Buffers& { } }(); - SurfaceComposerClient::Transaction t; - t.setTransform(mSurfaceControl, transform); - t.apply(); + createTransaction(mSurfaceControl).setTransform(mSurfaceControl, transform).apply(); BufferCache::const_iterator it = mBufferCache.find({fps.getIntValue(), transformHint}); if (it == mBufferCache.end()) { @@ -287,25 +289,21 @@ void RefreshRateOverlay::setViewport(ui::Size viewport) { Rect frame((3 * width) >> 4, height >> 5); frame.offsetBy(width >> 5, height >> 4); - SurfaceComposerClient::Transaction t; - t.setMatrix(mSurfaceControl, frame.getWidth() / static_cast(kBufferWidth), 0, 0, - frame.getHeight() / static_cast(kBufferHeight)); - t.setPosition(mSurfaceControl, frame.left, frame.top); - t.apply(); + createTransaction(mSurfaceControl) + .setMatrix(mSurfaceControl, frame.getWidth() / static_cast(kBufferWidth), 0, 0, + frame.getHeight() / static_cast(kBufferHeight)) + .setPosition(mSurfaceControl, frame.left, frame.top) + .apply(); } void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) { - SurfaceComposerClient::Transaction t; - t.setLayerStack(mSurfaceControl, stack); - t.apply(); + createTransaction(mSurfaceControl).setLayerStack(mSurfaceControl, stack).apply(); } void RefreshRateOverlay::changeRefreshRate(Fps fps) { mCurrentFps = fps; const auto buffer = getOrCreateBuffers(fps)[mFrame]; - SurfaceComposerClient::Transaction t; - t.setBuffer(mSurfaceControl, buffer); - t.apply(); + createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply(); } void RefreshRateOverlay::animate() { @@ -314,9 +312,7 @@ void RefreshRateOverlay::animate() { const auto& buffers = getOrCreateBuffers(*mCurrentFps); mFrame = (mFrame + 1) % buffers.size(); const auto buffer = buffers[mFrame]; - SurfaceComposerClient::Transaction t; - t.setBuffer(mSurfaceControl, buffer); - t.apply(); + createTransaction(mSurfaceControl).setBuffer(mSurfaceControl, buffer).apply(); } } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4c830307e8..64ba280f9c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3629,11 +3629,11 @@ uint32_t SurfaceFlinger::clearTransactionFlags(uint32_t mask) { } void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule, - const sp& applyToken) { + const sp& applyToken, FrameHint frameHint) { modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, applyToken); if (const bool scheduled = mTransactionFlags.fetch_or(mask) & mask; !scheduled) { - scheduleCommit(FrameHint::kActive); + scheduleCommit(frameHint); } } @@ -4005,7 +4005,7 @@ auto SurfaceFlinger::transactionIsReadyToBeApplied( } void SurfaceFlinger::queueTransaction(TransactionState& state) { - Mutex::Autolock _l(mQueueLock); + Mutex::Autolock lock(mQueueLock); // Generate a CountDownLatch pending state if this is a synchronous transaction. if ((state.flags & eSynchronous) || state.inputWindowCommands.syncInputWindows) { @@ -4024,7 +4024,9 @@ void SurfaceFlinger::queueTransaction(TransactionState& state) { return TransactionSchedule::Late; }(state.flags); - setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken); + const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone; + + setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint); } void SurfaceFlinger::waitForSynchronousTransaction( @@ -7172,15 +7174,6 @@ int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) con return calculateMaxAcquiredBufferCount(refreshRate, presentLatency); } -void TransactionState::traverseStatesWithBuffers( - std::function visitor) { - for (const auto& state : states) { - if (state.state.hasBufferChanges() && state.state.hasValidBuffer() && state.state.surface) { - visitor(state.state); - } - } -} - void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state) { sp layer = state.layer.promote(); if (!layer) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 97b0e8db5c..3c7facfc12 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -784,7 +784,8 @@ private: // Sets the masked bits, and schedules a commit if needed. void setTransactionFlags(uint32_t mask, TransactionSchedule = TransactionSchedule::Late, - const sp& applyToken = nullptr); + const sp& applyToken = nullptr, + FrameHint = FrameHint::kActive); // Clears and returns the masked bits. uint32_t clearTransactionFlags(uint32_t mask); diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h index 04ca347b2f..bab5326093 100644 --- a/services/surfaceflinger/TransactionState.h +++ b/services/surfaceflinger/TransactionState.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * 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. @@ -16,12 +16,21 @@ #pragma once +#include +#include +#include +#include + #include +#include namespace android { + class CountDownLatch; struct TransactionState { + TransactionState() = default; + TransactionState(const FrameTimelineInfo& frameTimelineInfo, const Vector& composerStates, const Vector& displayStates, uint32_t transactionFlags, @@ -47,9 +56,30 @@ struct TransactionState { originUid(originUid), id(transactionId) {} - TransactionState() {} + // Invokes `void(const layer_state_t&)` visitor for matching layers. + template + void traverseStatesWithBuffers(Visitor&& visitor) const { + for (const auto& [state] : states) { + if (state.hasBufferChanges() && state.hasValidBuffer() && state.surface) { + visitor(state); + } + } + } + + // TODO(b/185535769): Remove FrameHint. Instead, reset the idle timer (of the relevant physical + // display) on the main thread if commit leads to composite. Then, RefreshRateOverlay should be + // able to setFrameRate once, rather than for each transaction. + bool isFrameActive() const { + if (!displays.empty()) return true; + + for (const auto& [state] : states) { + if (state.frameRateCompatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE) { + return true; + } + } - void traverseStatesWithBuffers(std::function visitor); + return false; + } FrameTimelineInfo frameTimelineInfo; Vector states; diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 825f145ecd..b9a5f36794 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -337,10 +337,22 @@ TEST_F(SetFrameRateTest, ValidateFrameRate) { ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, "")); EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + // Privileged APIs. + EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + constexpr bool kPrivileged = true; EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "", - /*privileged=*/true)); + kPrivileged)); + EXPECT_TRUE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "", + kPrivileged)); + // Invalid frame rate. EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); EXPECT_FALSE(ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, @@ -348,15 +360,12 @@ TEST_F(SetFrameRateTest, ValidateFrameRate) { EXPECT_FALSE(ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - - // Invalid compatibility + // Invalid compatibility. EXPECT_FALSE( ValidateFrameRate(60.0f, -1, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); EXPECT_FALSE(ValidateFrameRate(60.0f, 2, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - // Invalid change frame rate strategy + // Invalid change frame rate strategy. EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, -1, "")); EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, 2, "")); } -- cgit v1.2.3-59-g8ed1b From 4cf2d8c799289459a23ed42244fef6f27359cd03 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Thu, 7 Apr 2022 14:52:00 +0000 Subject: Trace input only if the layer needs an input info It should skip trace the input if the layer don't need an input info. Or the 'fillInputInfo' would automatically fill the info if the layer would be checked in input. Bug: 227316706 Test: enabled winscope, enabled one hand mode. Change-Id: I64a3d6328e283d057c528ffda6af3b21cfaf44ee --- services/surfaceflinger/Layer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index f7e1d1ee95..d8a5601b8a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2185,7 +2185,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet layerInfo->set_owner_uid(mOwnerUid); - if (traceFlags & LayerTracing::TRACE_INPUT) { + if ((traceFlags & LayerTracing::TRACE_INPUT) && needsInputInfo()) { WindowInfo info; if (useDrawing) { info = fillInputInfo(ui::Transform(), /* displayIsSecure */ true); -- cgit v1.2.3-59-g8ed1b From 30fd9b9919ae4fbf32d5820c615039dc1a2881d3 Mon Sep 17 00:00:00 2001 From: chaviw Date: Fri, 22 Apr 2022 12:41:17 -0500 Subject: Send transaction callbacks even when no BSL The current transaction callback logic only accounts for 2 cases: 1. If there's a BSL in the transaction 2. If there are no layers in the transaction However, this doesn't account for cases where there's other layer types in the transaction that are not BSL. In those cases, we fail to invoke the transaction callbacks. Test: LayerCallbackTest Fixes: 229578553 Change-Id: I7483235617218a759bc9b1ea335e9fef80275728 --- services/surfaceflinger/Layer.cpp | 12 ++ services/surfaceflinger/Layer.h | 4 +- .../surfaceflinger/tests/LayerCallback_test.cpp | 121 ++++++++++++++++++--- 3 files changed, 119 insertions(+), 18 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d8a5601b8a..3a92ca49a2 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2664,6 +2664,18 @@ void Layer::cloneDrawingState(const Layer* from) { mDrawingState.callbackHandles = {}; } +bool Layer::setTransactionCompletedListeners(const std::vector>& handles) { + if (handles.empty()) { + return false; + } + + for (const auto& handle : handles) { + mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle); + } + + return true; +} + // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 565a6ff726..ecea74413c 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -431,9 +431,7 @@ public: virtual bool setApi(int32_t /*api*/) { return false; }; virtual bool setSidebandStream(const sp& /*sidebandStream*/) { return false; }; virtual bool setTransactionCompletedListeners( - const std::vector>& /*handles*/) { - return false; - }; + const std::vector>& /*handles*/); virtual bool addFrameEvent(const sp& /*acquireFence*/, nsecs_t /*postedTime*/, nsecs_t /*requestedPresentTime*/) { return false; diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 8a2305b365..219db8c148 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -55,24 +55,34 @@ public: return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState); } + static int fillBuffer(Transaction& transaction, const sp& layer, + bool setBuffer = true, bool setBackgroundColor = false) { + sp buffer; + sp fence; + if (setBuffer) { + int err = getBuffer(&buffer, &fence); + if (err != NO_ERROR) { + return err; + } + + transaction.setBuffer(layer, buffer, fence); + } + + if (setBackgroundColor) { + transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f, + ui::Dataspace::UNKNOWN); + } + + return NO_ERROR; + } + static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper, const sp& layer = nullptr, bool setBuffer = true, bool setBackgroundColor = false) { if (layer) { - sp buffer; - sp fence; - if (setBuffer) { - int err = getBuffer(&buffer, &fence); - if (err != NO_ERROR) { - return err; - } - - transaction.setBuffer(layer, buffer, fence); - } - - if (setBackgroundColor) { - transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f, - ui::Dataspace::UNKNOWN); + int err = fillBuffer(transaction, layer, setBuffer, setBackgroundColor); + if (err != NO_ERROR) { + return err; } } @@ -1115,7 +1125,7 @@ TEST_F(LayerCallbackTest, CommitCallbackOffscreenLayer) { Transaction transaction; CallbackHelper callback; int err = fillTransaction(transaction, &callback, layer, true); - err |= fillTransaction(transaction, &callback, offscreenLayer, true); + err |= fillBuffer(transaction, offscreenLayer); if (err) { GTEST_SUCCEED() << "test not supported"; return; @@ -1129,5 +1139,86 @@ TEST_F(LayerCallbackTest, CommitCallbackOffscreenLayer) { committedSc.insert(layer); committedSc.insert(offscreenLayer); EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc)); + + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); + expected.addSurface(ExpectedResult::Transaction::PRESENTED, offscreenLayer); + EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); } + +TEST_F(LayerCallbackTest, TransactionCommittedCallback_BSL) { + sp layer; + ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + + Transaction transaction; + CallbackHelper callback; + int err = fillTransaction(transaction, &callback, layer, true); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply(); + std::unordered_set, SCHash> committedSc; + committedSc.insert(layer); + EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc)); + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); + EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); +} + +TEST_F(LayerCallbackTest, TransactionCommittedCallback_EffectLayer) { + sp layer; + ASSERT_NO_FATAL_FAILURE(layer = createColorLayer("ColorLayer", Color::RED)); + + Transaction transaction; + CallbackHelper callback; + int err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply(); + std::unordered_set, SCHash> committedSc; + EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc)); + + ExpectedResult expected; + EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); +} + +TEST_F(LayerCallbackTest, TransactionCommittedCallback_ContainerLayer) { + sp layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer(mClient, "Container Layer", 0, 0, + ISurfaceComposerClient::eFXSurfaceContainer)); + + Transaction transaction; + CallbackHelper callback; + int err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply(); + std::unordered_set, SCHash> committedSc; + EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc)); + + ExpectedResult expected; + EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); +} + +TEST_F(LayerCallbackTest, TransactionCommittedCallback_NoLayer) { + Transaction transaction; + CallbackHelper callback; + int err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + transaction.addTransactionCommittedCallback(callback.function, callback.getContext()).apply(); + std::unordered_set, SCHash> committedSc; + EXPECT_NO_FATAL_FAILURE(waitForCommitCallback(callback, committedSc)); + + ExpectedResult expected; + EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); +} + } // namespace android -- cgit v1.2.3-59-g8ed1b From dda07d9be6dd032cd1bba422d94fa1fc6af69a4e Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 25 Apr 2022 22:39:25 +0000 Subject: Allow SurfaceFlinger to treat 170M as sRGB. Introduce a debug sysprop, defaulted to false, to allow for rewriting the transfer function to sRGB when set to true. This is due to several considerations: 1. SurfaceFlinger has not color managed SMPTE 170M properly ever since color management was introduced in Android O, and was only fixed in Android 13. This means that some camera -> encoding -> storage -> playback flows may be incorrectly calibrated on some devices since SMPTE 170M was reinterpreted as sRGB for a long time. 2. BT. 1886 recommends a reference EOTF of gamma 2.4 with tuneable parameters to approximate a CRT on a non-CRT display. Because the framework doesn't support BT. 1886 and it's too late to add support, casting as sRGB is probably okay for now and matches old behavior. 3. Typical Rec. 709 content is graded assuming a dim surround, but phone displays are used in a wide range of viewing environments, which means that viewing Rec. 709 content in a bright environment may appear to have lower contrast. Decoding as sRGB will push the dark codes into lower luminance levels, which will improve contrast in those scenarios. Note that it's better to adjust contrast based on the ambient viewing environment, but again it's too late for Android 13 to improve the color pipeline in the GPU. Bug: 229442032 Test: Photos playback after recording a video Change-Id: I64fc8f2ea77f8e595333de36fb9da2979d8316ca --- .../include/compositionengine/Output.h | 3 +++ .../include/compositionengine/impl/Output.h | 1 + .../compositionengine/impl/OutputCompositionState.h | 2 ++ .../include/compositionengine/mock/Output.h | 1 + .../surfaceflinger/CompositionEngine/src/Output.cpp | 4 ++++ .../CompositionEngine/src/OutputCompositionState.cpp | 3 +++ .../CompositionEngine/src/OutputLayer.cpp | 11 +++++++++++ .../CompositionEngine/tests/OutputLayerTest.cpp | 17 +++++++++++++++++ .../CompositionEngine/tests/OutputTest.cpp | 14 ++++++++++++++ services/surfaceflinger/DisplayDevice.cpp | 1 + services/surfaceflinger/Layer.cpp | 13 +++++++++++++ services/surfaceflinger/SurfaceFlinger.cpp | 3 +++ services/surfaceflinger/SurfaceFlinger.h | 6 ++++++ 13 files changed, 79 insertions(+) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 5846e674f5..db2fd1b500 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -267,6 +267,9 @@ public: // Enables predicting composition strategy to run client composition earlier virtual void setPredictCompositionStrategy(bool) = 0; + // Enables overriding the 170M trasnfer function as sRGB + virtual void setTreat170mAsSrgb(bool) = 0; + protected: virtual void setDisplayColorProfile(std::unique_ptr) = 0; virtual void setRenderSurface(std::unique_ptr) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 0feb9f7fb7..31c51e6a8d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -108,6 +108,7 @@ public: void cacheClientCompositionRequests(uint32_t) override; bool canPredictCompositionStrategy(const CompositionRefreshArgs&) override; void setPredictCompositionStrategy(bool) override; + void setTreat170mAsSrgb(bool) override; // Testing const ReleasedLayers& getReleasedLayersForTest() const; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 61be983480..c65d467b0d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -162,6 +162,8 @@ struct OutputCompositionState { CompositionStrategyPredictionState strategyPrediction = CompositionStrategyPredictionState::DISABLED; + bool treat170mAsSrgb = false; + // 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 fa86076b44..cb9fbad8dd 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -132,6 +132,7 @@ public: MOCK_METHOD1(cacheClientCompositionRequests, void(uint32_t)); MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&)); MOCK_METHOD1(setPredictCompositionStrategy, void(bool)); + MOCK_METHOD1(setTreat170mAsSrgb, void(bool)); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index ec8673177f..4c30f99610 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -1488,6 +1488,10 @@ void Output::setPredictCompositionStrategy(bool predict) { } } +void Output::setTreat170mAsSrgb(bool enable) { + editState().treat170mAsSrgb = enable; +} + bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) { if (!getState().isEnabled || !mHwComposerAsyncWorker) { ALOGV("canPredictCompositionStrategy disabled"); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index 3b85e3b5b0..948c0c90bf 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -66,6 +66,9 @@ void OutputCompositionState::dump(std::string& out) const { out.append("\n "); dumpVal(out, "compositionStrategyPredictionState", ftl::enum_string(strategyPrediction)); + out.append("\n "); + dumpVal(out, "treate170mAsSrgb", treat170mAsSrgb); + out += '\n'; } diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 3289d55870..61c53df38d 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -322,6 +322,17 @@ void OutputLayer::updateCompositionState( ? outputState.targetDataspace : layerFEState->dataspace; + // Override the dataspace transfer from 170M to sRGB if the device configuration requests this. + // We do this here instead of in buffer info so that dumpsys can still report layers that are + // using the 170M transfer. Also we only do this if the colorspace is not agnostic for the + // layer, in case the color profile uses a 170M transfer function. + if (outputState.treat170mAsSrgb && !layerFEState->isColorspaceAgnostic && + (state.dataspace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_SMPTE_170M) { + state.dataspace = static_cast( + (state.dataspace & HAL_DATASPACE_STANDARD_MASK) | + (state.dataspace & HAL_DATASPACE_RANGE_MASK) | HAL_DATASPACE_TRANSFER_SRGB); + } + // For hdr content, treat the white point as the display brightness - HDR content should not be // boosted or dimmed. // If the layer explicitly requests to disable dimming, then don't dim either. diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index ceee48c1ef..ca4f39729a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -657,6 +657,23 @@ TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceCorrectly EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace); } +TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceWith170mReplacement) { + mLayerFEState.dataspace = ui::Dataspace::TRANSFER_SMPTE_170M; + mOutputState.targetDataspace = ui::Dataspace::V0_SCRGB; + mOutputState.treat170mAsSrgb = false; + mLayerFEState.isColorspaceAgnostic = false; + + mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0); + + EXPECT_EQ(ui::Dataspace::TRANSFER_SMPTE_170M, mOutputLayer.getState().dataspace); + + // Rewrite SMPTE 170M as sRGB + mOutputState.treat170mAsSrgb = true; + mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0); + + EXPECT_EQ(ui::Dataspace::TRANSFER_SRGB, mOutputLayer.getState().dataspace); +} + TEST_F(OutputLayerUpdateCompositionStateTest, setsWhitePointNitsAndDimmingRatioCorrectly) { mOutputState.sdrWhitePointNits = 200.f; mOutputState.displayBrightnessNits = 800.f; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 42c8b37710..3a3c91e518 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -247,6 +247,20 @@ TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) { EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } +/* + * Output::setTreat170mAsSrgb() + */ + +TEST_F(OutputTest, setTreat170mAsSrgb) { + EXPECT_FALSE(mOutput->getState().treat170mAsSrgb); + + mOutput->setTreat170mAsSrgb(true); + EXPECT_TRUE(mOutput->getState().treat170mAsSrgb); + + mOutput->setTreat170mAsSrgb(false); + EXPECT_FALSE(mOutput->getState().treat170mAsSrgb); +} + /* * Output::setLayerCachingEnabled() */ diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 52529d6b04..a915b615d9 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -89,6 +89,7 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) } mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy); + mCompositionDisplay->setTreat170mAsSrgb(mFlinger->mTreat170mAsSrgb); mCompositionDisplay->createDisplayColorProfile( compositionengine::DisplayColorProfileCreationArgsBuilder() .setHasWideColorGamut(args.hasWideColorGamut) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3a92ca49a2..e1eec8b97e 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -600,6 +601,18 @@ std::optional Layer::prepareClientCom layerSettings.alpha = alpha; layerSettings.sourceDataspace = getDataSpace(); + // Override the dataspace transfer from 170M to sRGB if the device configuration requests this. + // We do this here instead of in buffer info so that dumpsys can still report layers that are + // using the 170M transfer. + if (mFlinger->mTreat170mAsSrgb && + (layerSettings.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) == + HAL_DATASPACE_TRANSFER_SMPTE_170M) { + layerSettings.sourceDataspace = static_cast( + (layerSettings.sourceDataspace & HAL_DATASPACE_STANDARD_MASK) | + (layerSettings.sourceDataspace & HAL_DATASPACE_RANGE_MASK) | + HAL_DATASPACE_TRANSFER_SRGB); + } + layerSettings.whitePointNits = targetSettings.whitePointNits; switch (targetSettings.blurSetting) { case LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled: diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d39176be14..65c1c97efb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -419,6 +419,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("debug.sf.predict_hwc_composition_strategy", value, "1"); mPredictCompositionStrategy = atoi(value); + property_get("debug.sf.treat_170m_as_sRGB", value, "0"); + mTreat170mAsSrgb = atoi(value); + // We should be reading 'persist.sys.sf.color_saturation' here // but since /data may be encrypted, we need to wait until after vold // comes online to attempt to read the property. The property is diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 74e0407215..c70e1749ff 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -349,6 +349,12 @@ public: // run parallel to the hwc validateDisplay call and re-run if the predition is incorrect. bool mPredictCompositionStrategy = false; + // If true, then any layer with a SMPTE 170M transfer function is decoded using the sRGB + // transfer instead. This is mainly to preserve legacy behavior, where implementations treated + // SMPTE 170M as sRGB prior to color management being implemented, and now implementations rely + // on this behavior to increase contrast for some media sources. + bool mTreat170mAsSrgb = false; + protected: // We're reference counted, never destroy SurfaceFlinger directly virtual ~SurfaceFlinger(); -- cgit v1.2.3-59-g8ed1b From c3f39b1a6b3882767fd633b09e2002ce5091d8da Mon Sep 17 00:00:00 2001 From: chaviw Date: Fri, 10 Sep 2021 13:41:39 -0500 Subject: Add isClone to WindowInfo Add a flag about whether the window is a clone to help identity the original windows vs clones Test: WindowInfo_test Bug: 230300971 Change-Id: Idb890482a86243790407abe83732e3ca7c7cfdba --- libs/gui/WindowInfo.cpp | 8 +++++--- libs/gui/include/gui/WindowInfo.h | 2 ++ libs/gui/tests/WindowInfo_test.cpp | 2 ++ services/surfaceflinger/Layer.cpp | 1 + 4 files changed, 10 insertions(+), 3 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 804ce4fac0..4e966d1393 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -76,7 +76,7 @@ bool WindowInfo::operator==(const WindowInfo& info) const { info.inputConfig == inputConfig && info.displayId == displayId && info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType && - info.layoutParamsFlags == layoutParamsFlags; + info.layoutParamsFlags == layoutParamsFlags && info.isClone == isClone; } status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { @@ -124,7 +124,8 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->write(touchableRegion) ?: parcel->writeBool(replaceTouchableRegionWithCrop) ?: parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?: - parcel->writeStrongBinder(windowToken); + parcel->writeStrongBinder(windowToken) ?: + parcel->writeBool(isClone); // clang-format on return status; } @@ -175,7 +176,8 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->read(touchableRegion) ?: parcel->readBool(&replaceTouchableRegionWithCrop) ?: parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?: - parcel->readNullableStrongBinder(&windowToken); + parcel->readNullableStrongBinder(&windowToken) ?: + parcel->readBool(&isClone); // clang-format on if (status != OK) { diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 0e1d25812e..169f7f022b 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -236,6 +236,8 @@ struct WindowInfo : public Parcelable { void setInputConfig(ftl::Flags config, bool value); + bool isClone = false; + void addTouchableRegion(const Rect& region); bool touchableRegionContainsPoint(int32_t x, int32_t y) const; diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index c51b244c50..99658ccd4b 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -71,6 +71,7 @@ TEST(WindowInfo, Parcelling) { i.applicationInfo.name = "ApplicationFooBar"; i.applicationInfo.token = new BBinder(); i.applicationInfo.dispatchingTimeoutMillis = 0x12345678ABCD; + i.isClone = true; Parcel p; i.writeToParcel(&p); @@ -101,6 +102,7 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop); ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle); ASSERT_EQ(i.applicationInfo, i2.applicationInfo); + ASSERT_EQ(i.isClone, i2.isClone); } TEST(InputApplicationInfo, Parcelling) { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index e1eec8b97e..a1e2c0d39a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2430,6 +2430,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp // If the layer is a clone, we need to crop the input region to cloned root to prevent // touches from going outside the cloned area. if (isClone()) { + info.isClone = true; if (const sp clonedRoot = getClonedRoot()) { const Rect rect = displayTransform.transform(Rect{clonedRoot->mScreenBounds}); info.touchableRegion = info.touchableRegion.intersect(rect); -- cgit v1.2.3-59-g8ed1b From 8977ce95657dd39d9b814bc4d2a4ca7817e425e0 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Sat, 7 May 2022 00:34:50 +0000 Subject: Remove consumer frame event history At this point only used in a part of dumpsys that no one checks, and is churning a bunch of fd cost. Bug: 231762515 Test: builds Change-Id: Iaaba87a236971920b302960c5a09d9c01253d562 --- services/surfaceflinger/BufferLayer.cpp | 15 ++------- services/surfaceflinger/BufferLayer.h | 2 +- services/surfaceflinger/BufferLayerConsumer.cpp | 12 ------- services/surfaceflinger/BufferLayerConsumer.h | 3 +- services/surfaceflinger/BufferQueueLayer.cpp | 19 ++--------- services/surfaceflinger/BufferQueueLayer.h | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 30 +---------------- services/surfaceflinger/BufferStateLayer.h | 4 +-- services/surfaceflinger/Layer.cpp | 38 ---------------------- services/surfaceflinger/Layer.h | 14 -------- services/surfaceflinger/SurfaceFlinger.cpp | 8 ----- services/surfaceflinger/SurfaceFlinger.h | 2 -- .../fuzzer/surfaceflinger_fuzzers_utils.h | 3 -- .../fuzzer/surfaceflinger_layer_fuzzer.cpp | 2 -- 14 files changed, 10 insertions(+), 144 deletions(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 635b0884d9..f8c53c338e 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -315,11 +315,7 @@ void BufferLayer::preparePerFrameCompositionState() { compositionState->sidebandStreamHasFrame = false; } -bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) { - if (mBufferInfo.mBuffer != nullptr) { - Mutex::Autolock lock(mFrameEventHistoryMutex); - mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime); - } +bool BufferLayer::onPreComposition(nsecs_t) { return hasReadyFrame(); } namespace { @@ -365,12 +361,7 @@ void BufferLayer::onPostComposition(const DisplayDevice* display, mAlreadyDisplayedThisCompose = false; // Update mFrameEventHistory. - { - Mutex::Autolock lock(mFrameEventHistoryMutex); - mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence, - compositorTiming); - finalizeFrameEventHistory(glDoneFence, compositorTiming); - } + finalizeFrameEventHistory(glDoneFence, compositorTiming); // Update mFrameTracker. nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime; @@ -500,7 +491,7 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, return false; } - err = updateFrameNumber(latchTime); + err = updateFrameNumber(); if (err != NO_ERROR) { return false; } diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 3e70493101..4c70eb58bf 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -192,7 +192,7 @@ private: nsecs_t expectedPresentTime) = 0; virtual status_t updateActiveBuffer() = 0; - virtual status_t updateFrameNumber(nsecs_t latchTime) = 0; + virtual status_t updateFrameNumber() = 0; // We generate InputWindowHandles for all non-cursor buffered layers regardless of whether they // have an InputChannel. This is to enable the InputDispatcher to do PID based occlusion diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 9ae45fc4cb..7361a4fdef 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -471,18 +471,6 @@ void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) { } } -void BufferLayerConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, - FrameEventHistoryDelta* outDelta) { - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - // Nothing to do if we're already abandoned. - return; - } - - mLayer->addAndGetFrameTimestamps(newTimestamps, outDelta); -} - void BufferLayerConsumer::abandonLocked() { BLC_LOGV("abandonLocked"); mCurrentTextureBuffer = nullptr; diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index 9ed80b46bd..23ad2a3f91 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -236,8 +236,7 @@ private: // IConsumerListener interface void onDisconnect() override; void onSidebandStreamChanged() override; - void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, - FrameEventHistoryDelta* outDelta) override; + void addAndGetFrameTimestamps(const NewFrameEventsEntry*, FrameEventHistoryDelta*) override {} // computeCurrentTransformMatrixLocked computes the transform matrix for the // current texture. It uses mCurrentTransform and the current GraphicBuffer diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 926aa1dfb2..50146d7907 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -67,20 +67,10 @@ void BufferQueueLayer::setTransformHint(ui::Transform::RotationFlags displayTran mConsumer->setTransformHint(mTransformHint); } -void BufferQueueLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { +void BufferQueueLayer::releasePendingBuffer(nsecs_t) { if (!mConsumer->releasePendingBuffer()) { return; } - - auto releaseFenceTime = std::make_shared(mConsumer->getPrevFinalReleaseFence()); - mReleaseTimeline.updateSignalTimes(); - mReleaseTimeline.push(releaseFenceTime); - - Mutex::Autolock lock(mFrameEventHistoryMutex); - if (mPreviousFrameNumber != 0) { - mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime, - std::move(releaseFenceTime)); - } } void BufferQueueLayer::setDefaultBufferSize(uint32_t w, uint32_t h) { @@ -320,14 +310,9 @@ status_t BufferQueueLayer::updateActiveBuffer() { return NO_ERROR; } -status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) { +status_t BufferQueueLayer::updateFrameNumber() { mPreviousFrameNumber = mCurrentFrameNumber; mCurrentFrameNumber = mConsumer->getFrameNumber(); - - { - Mutex::Autolock lock(mFrameEventHistoryMutex); - mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime); - } return NO_ERROR; } diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index c6e0727806..cca7f707fc 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -103,7 +103,7 @@ private: nsecs_t expectedPresentTime) override; status_t updateActiveBuffer() override; - status_t updateFrameNumber(nsecs_t latchTime) override; + status_t updateFrameNumber() override; void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) override; sp createClone() override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index c5d7a601c5..af0039cd2c 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -179,15 +179,6 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { } mDrawingState.callbackHandles = {}; - - std::shared_ptr releaseFenceTime = std::make_shared(releaseFence); - { - Mutex::Autolock lock(mFrameEventHistoryMutex); - if (mPreviousFrameNumber != 0) { - mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime, - std::move(releaseFenceTime)); - } - } } void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr& glDoneFence, @@ -347,19 +338,6 @@ bool BufferStateLayer::setPosition(float x, float y) { return true; } -bool BufferStateLayer::addFrameEvent(const sp& acquireFence, nsecs_t postedTime, - nsecs_t desiredPresentTime) { - Mutex::Autolock lock(mFrameEventHistoryMutex); - mAcquireTimeline.updateSignalTimes(); - std::shared_ptr acquireFenceTime = - std::make_shared((acquireFence ? acquireFence : Fence::NO_FENCE)); - NewFrameEventsEntry newTimestamps = {mDrawingState.frameNumber, postedTime, desiredPresentTime, - acquireFenceTime}; - mFrameEventHistory.setProducerWantsEvents(); - mFrameEventHistory.addQueue(newTimestamps); - return true; -} - bool BufferStateLayer::setBuffer(std::shared_ptr& buffer, const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp, @@ -446,8 +424,6 @@ bool BufferStateLayer::setBuffer(std::shared_ptr& using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer); - addFrameEvent(mDrawingState.acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime); - setFrameTimelineVsyncForBufferTransaction(info, postTime); if (dequeueTime && *dequeueTime != 0) { @@ -727,14 +703,10 @@ status_t BufferStateLayer::updateActiveBuffer() { return NO_ERROR; } -status_t BufferStateLayer::updateFrameNumber(nsecs_t latchTime) { +status_t BufferStateLayer::updateFrameNumber() { // TODO(marissaw): support frame history events mPreviousFrameNumber = mCurrentFrameNumber; mCurrentFrameNumber = mDrawingState.frameNumber; - { - Mutex::Autolock lock(mFrameEventHistoryMutex); - mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime); - } return NO_ERROR; } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 8a696f11b4..e98aa9abf9 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -67,8 +67,6 @@ public: bool setApi(int32_t api) override; bool setSidebandStream(const sp& sidebandStream) override; bool setTransactionCompletedListeners(const std::vector>& handles) override; - bool addFrameEvent(const sp& acquireFence, nsecs_t postedTime, - nsecs_t requestedPresentTime) override; bool setPosition(float /*x*/, float /*y*/) override; bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/); @@ -125,7 +123,7 @@ private: nsecs_t expectedPresentTime) override; status_t updateActiveBuffer() override; - status_t updateFrameNumber(nsecs_t latchTime) override; + status_t updateFrameNumber() override; sp createClone() override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index e1eec8b97e..e4859c1354 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -151,10 +151,8 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.color.g = -1.0_hf; mDrawingState.color.b = -1.0_hf; } - CompositorTiming compositorTiming; args.flinger->getCompositorTiming(&compositorTiming); - mFrameEventHistory.initializeCompositorTiming(compositorTiming); mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval); mCallingPid = args.callingPid; @@ -1532,53 +1530,17 @@ void Layer::getFrameStats(FrameStats* outStats) const { mFrameTracker.getStats(outStats); } -void Layer::dumpFrameEvents(std::string& result) { - StringAppendF(&result, "- Layer %s (%s, %p)\n", getName().c_str(), getType(), this); - Mutex::Autolock lock(mFrameEventHistoryMutex); - mFrameEventHistory.checkFencesForCompletion(); - mFrameEventHistory.dump(result); -} - void Layer::dumpCallingUidPid(std::string& result) const { StringAppendF(&result, "Layer %s (%s) callingPid:%d callingUid:%d ownerUid:%d\n", getName().c_str(), getType(), mCallingPid, mCallingUid, mOwnerUid); } void Layer::onDisconnect() { - Mutex::Autolock lock(mFrameEventHistoryMutex); - mFrameEventHistory.onDisconnect(); const int32_t layerId = getSequence(); mFlinger->mTimeStats->onDestroy(layerId); mFlinger->mFrameTracer->onDestroy(layerId); } -void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, - FrameEventHistoryDelta* outDelta) { - if (newTimestamps) { - mFlinger->mTimeStats->setPostTime(getSequence(), newTimestamps->frameNumber, - getName().c_str(), mOwnerUid, newTimestamps->postedTime, - getGameMode()); - mFlinger->mTimeStats->setAcquireFence(getSequence(), newTimestamps->frameNumber, - newTimestamps->acquireFence); - } - - Mutex::Autolock lock(mFrameEventHistoryMutex); - if (newTimestamps) { - // If there are any unsignaled fences in the aquire timeline at this - // point, the previously queued frame hasn't been latched yet. Go ahead - // and try to get the signal time here so the syscall is taken out of - // the main thread's critical path. - mAcquireTimeline.updateSignalTimes(); - // Push the new fence after updating since it's likely still pending. - mAcquireTimeline.push(newTimestamps->acquireFence); - mFrameEventHistory.addQueue(*newTimestamps); - } - - if (outDelta) { - mFrameEventHistory.getAndResetDelta(outDelta); - } -} - size_t Layer::getChildrenCount() const { size_t count = 0; for (const sp& child : mCurrentChildren) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index ecea74413c..0b63fabe50 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -432,10 +432,6 @@ public: virtual bool setSidebandStream(const sp& /*sidebandStream*/) { return false; }; virtual bool setTransactionCompletedListeners( const std::vector>& /*handles*/); - virtual bool addFrameEvent(const sp& /*acquireFence*/, nsecs_t /*postedTime*/, - nsecs_t /*requestedPresentTime*/) { - return false; - } virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace); virtual bool setColorSpaceAgnostic(const bool agnostic); virtual bool setDimmingEnabled(const bool dimmingEnabled); @@ -743,14 +739,11 @@ public: void miniDump(std::string& result, const DisplayDevice&) const; void dumpFrameStats(std::string& result) const; - void dumpFrameEvents(std::string& result); void dumpCallingUidPid(std::string& result) const; void clearFrameStats(); void logFrameStats(); void getFrameStats(FrameStats* outStats) const; void onDisconnect(); - void addAndGetFrameTimestamps(const NewFrameEventsEntry* newEntry, - FrameEventHistoryDelta* outDelta); ui::Transform getTransform() const; bool isTransformValid() const; @@ -995,13 +988,6 @@ protected: // Timestamp history for UIAutomation. Thread safe. FrameTracker mFrameTracker; - // Timestamp history for the consumer to query. - // Accessed by both consumer and producer on main and binder threads. - Mutex mFrameEventHistoryMutex; - ConsumerFrameEventHistory mFrameEventHistory; - FenceTimeline mAcquireTimeline; - FenceTimeline mReleaseTimeline; - // main thread sp mSidebandStream; // False if the buffer and its contents have been previously used for GPU diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e6b64c15e9..47478f7ecc 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4974,7 +4974,6 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { {"--displays"s, dumper(&SurfaceFlinger::dumpDisplays)}, {"--dispsync"s, dumper([this](std::string& s) { mScheduler->dumpVsync(s); })}, {"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)}, - {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)}, {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)}, {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)}, {"--list"s, dumper(&SurfaceFlinger::listLayersLocked)}, @@ -5141,13 +5140,6 @@ void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const { bucketTimeSec, percent); } -void SurfaceFlinger::dumpFrameEventsLocked(std::string& result) { - result.append("Layer frame timestamps:\n"); - // Traverse all layers to dump frame-events for each layer - mCurrentState.traverseInZOrder( - [&] (Layer* layer) { layer->dumpFrameEvents(result); }); -} - void SurfaceFlinger::dumpCompositionDisplays(std::string& result) const { for (const auto& [token, display] : mDisplays) { display->getCompositionDisplay()->dump(result); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index fc27b62b33..db5fd470c5 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1098,8 +1098,6 @@ private: void dumpVSync(std::string& result) const REQUIRES(mStateLock); void dumpStaticScreenStats(std::string& result) const; - // Not const because each Layer needs to query Fences and cache timestamps. - void dumpFrameEventsLocked(std::string& result); void dumpCompositionDisplays(std::string& result) const REQUIRES(mStateLock); void dumpDisplays(std::string& result) const REQUIRES(mStateLock); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index a80aca2f73..867a1985bd 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -455,9 +455,6 @@ public: result = fdp->ConsumeRandomLengthString().c_str(); mFlinger->dumpStaticScreenStats(result); - result = fdp->ConsumeRandomLengthString().c_str(); - mFlinger->dumpFrameEventsLocked(result); - result = fdp->ConsumeRandomLengthString().c_str(); mFlinger->dumpRawDisplayIdentificationData(dumpArgs, result); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp index 46d52dd221..8b58298766 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp @@ -146,8 +146,6 @@ void LayerFuzzer::invokeBufferStateLayer() { const bool ownsHandle = mFdp.ConsumeBool(); sp nativeHandle = sp::make(testHandle, ownsHandle); layer->setSidebandStream(nativeHandle); - layer->addFrameEvent(fence, mFdp.ConsumeIntegral() /*postedTime*/, - mFdp.ConsumeIntegral() /*requestedTime*/); layer->computeSourceBounds(getFuzzedFloatRect(&mFdp)); layer->fenceHasSignaled(); -- cgit v1.2.3-59-g8ed1b From bb448ce9aa521f9574d94c9ec2d57eb7d37382cb Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sat, 7 May 2022 15:52:55 -0700 Subject: SF: Do not duplicate fences per layer per frame Convert the unique_fd of RenderEngineResult (and futures thereof) into sp such that postFramebuffer does not duplicate release/present fences. Remove a few copies of shared futures/pointers with std::move. Bug: 232436803 Test: simpleperf (-33% cycles in sys_dup) Change-Id: Ia7c6c8333a712441f3612fb5c720ea2932799636 --- services/surfaceflinger/BufferQueueLayer.cpp | 5 +- services/surfaceflinger/BufferQueueLayer.h | 3 +- services/surfaceflinger/BufferStateLayer.cpp | 5 +- services/surfaceflinger/BufferStateLayer.h | 3 +- .../include/compositionengine/FenceResult.h | 49 +++++++++ .../include/compositionengine/LayerFE.h | 5 +- .../include/compositionengine/mock/LayerFE.h | 2 +- .../CompositionEngine/src/Output.cpp | 43 ++++---- .../CompositionEngine/src/planner/CachedSet.cpp | 15 +-- .../CompositionEngine/tests/OutputTest.cpp | 54 ++++------ services/surfaceflinger/Layer.cpp | 3 +- services/surfaceflinger/Layer.h | 3 +- services/surfaceflinger/RegionSamplingThread.cpp | 15 +-- services/surfaceflinger/SurfaceFlinger.cpp | 117 ++++++++++----------- services/surfaceflinger/SurfaceFlinger.h | 12 ++- .../surfaceflinger/TransactionCallbackInvoker.cpp | 13 +-- .../surfaceflinger/TransactionCallbackInvoker.h | 4 +- .../fuzzer/surfaceflinger_layer_fuzzer.cpp | 11 +- .../tests/unittests/CompositionTest.cpp | 13 ++- 19 files changed, 201 insertions(+), 174 deletions(-) create mode 100644 services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 926aa1dfb2..6a1a38b39c 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -48,9 +48,8 @@ BufferQueueLayer::~BufferQueueLayer() { // Interface implementation for Layer // ----------------------------------------------------------------------- -void BufferQueueLayer::onLayerDisplayed( - std::shared_future futureRenderEngineResult) { - sp releaseFence = new Fence(dup(futureRenderEngineResult.get().drawFence)); +void BufferQueueLayer::onLayerDisplayed(std::shared_future futureFenceResult) { + const sp releaseFence = futureFenceResult.get().value_or(Fence::NO_FENCE); mConsumer->setReleaseFence(releaseFence); // Prevent tracing the same release multiple times. diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index c6e0727806..4587b5e27c 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -42,8 +42,7 @@ public: // Implements Layer. const char* getType() const override { return "BufferQueueLayer"; } - void onLayerDisplayed( - std::shared_future futureRenderEngineResult) override; + void onLayerDisplayed(std::shared_future) override; // If a buffer was replaced this frame, release the former buffer void releasePendingBuffer(nsecs_t dequeueReadyTime) override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index c5d7a601c5..c88511049b 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -73,8 +73,7 @@ BufferStateLayer::~BufferStateLayer() { // ----------------------------------------------------------------------- // Interface implementation for Layer // ----------------------------------------------------------------------- -void BufferStateLayer::onLayerDisplayed( - std::shared_future futureRenderEngineResult) { +void BufferStateLayer::onLayerDisplayed(std::shared_future futureFenceResult) { // If we are displayed on multiple displays in a single composition cycle then we would // need to do careful tracking to enable the use of the mLastClientCompositionFence. // For example we can only use it if all the displays are client comp, and we need @@ -118,7 +117,7 @@ void BufferStateLayer::onLayerDisplayed( if (ch != nullptr) { ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; - ch->previousReleaseFences.emplace_back(futureRenderEngineResult); + ch->previousReleaseFences.emplace_back(std::move(futureFenceResult)); ch->name = mName; } } diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 8a696f11b4..cc510d8c74 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -39,8 +39,7 @@ public: // Implements Layer. const char* getType() const override { return "BufferStateLayer"; } - void onLayerDisplayed( - std::shared_future futureRenderEngineResult) override; + void onLayerDisplayed(std::shared_future) override; void releasePendingBuffer(nsecs_t dequeueReadyTime) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h new file mode 100644 index 0000000000..0ce263b930 --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/FenceResult.h @@ -0,0 +1,49 @@ +/* + * Copyright 2022 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 + +// TODO(b/232535621): Pull this file to so that RenderEngine::drawLayers returns +// FenceResult rather than RenderEngineResult. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#include +#pragma clang diagnostic pop + +namespace android { + +class Fence; + +using FenceResult = base::expected, status_t>; + +// TODO(b/232535621): Prevent base::unexpected(NO_ERROR) from being a valid FenceResult. +inline status_t fenceStatus(const FenceResult& fenceResult) { + return fenceResult.ok() ? NO_ERROR : fenceResult.error(); +} + +inline FenceResult toFenceResult(renderengine::RenderEngineResult&& result) { + if (auto [status, fence] = std::move(result); fence.ok()) { + return sp::make(std::move(fence)); + } else { + return base::unexpected(status); + } +} + +} // namespace android diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index e77e155cb8..b7fc62fd21 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -21,13 +21,14 @@ #include #include +#include + // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wextra" #include -#include // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" @@ -156,7 +157,7 @@ public: ClientCompositionTargetSettings&) = 0; // Called after the layer is displayed to update the presentation fence - virtual void onLayerDisplayed(std::shared_future) = 0; + virtual void onLayerDisplayed(std::shared_future) = 0; // Gets some kind of identifier for the layer for debug purposes. virtual const char* getDebugName() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index ee0c53ded7..871599d2cd 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -49,7 +49,7 @@ public: std::vector( compositionengine::LayerFE::ClientCompositionTargetSettings&)); - MOCK_METHOD1(onLayerDisplayed, void(std::shared_future)); + MOCK_METHOD1(onLayerDisplayed, void(std::shared_future)); MOCK_CONST_METHOD0(getDebugName, const char*()); MOCK_CONST_METHOD0(getSequence, int32_t()); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 4c30f99610..742332ca24 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -1245,34 +1245,31 @@ std::optional Output::composeSurfaces( // probably to encapsulate the output buffer into a structure that dispatches resource cleanup // over to RenderEngine, in which case this flag can be removed from the drawLayers interface. const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay; - auto [status, drawFence] = - renderEngine - .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, tex, - useFramebufferCache, std::move(fd)) - .get(); - if (status != NO_ERROR && mClientCompositionRequestCache) { + auto fenceResult = + toFenceResult(renderEngine + .drawLayers(clientCompositionDisplay, clientRenderEngineLayers, + tex, useFramebufferCache, std::move(fd)) + .get()); + + if (mClientCompositionRequestCache && fenceStatus(fenceResult) != NO_ERROR) { // If rendering was not successful, remove the request from the cache. mClientCompositionRequestCache->remove(tex->getBuffer()->getId()); } - auto& timeStats = getCompositionEngine().getTimeStats(); - if (drawFence.get() < 0) { - timeStats.recordRenderEngineDuration(renderEngineStart, systemTime()); + const auto fence = std::move(fenceResult).value_or(Fence::NO_FENCE); + + if (auto& timeStats = getCompositionEngine().getTimeStats(); fence->isValid()) { + timeStats.recordRenderEngineDuration(renderEngineStart, std::make_shared(fence)); } else { - timeStats.recordRenderEngineDuration(renderEngineStart, - std::make_shared( - new Fence(dup(drawFence.get())))); + timeStats.recordRenderEngineDuration(renderEngineStart, systemTime()); } - if (clientCompositionLayersFE.size() > 0) { - sp clientCompFence = new Fence(dup(drawFence.get())); - for (auto clientComposedLayer : clientCompositionLayersFE) { - clientComposedLayer->setWasClientComposed(clientCompFence); - } + for (auto* clientComposedLayer : clientCompositionLayersFE) { + clientComposedLayer->setWasClientComposed(fence); } - return std::move(drawFence); + return base::unique_fd(fence->dup()); } std::vector Output::generateClientCompositionRequests( @@ -1429,19 +1426,15 @@ void Output::postFramebuffer() { Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence); } layer->getLayerFE().onLayerDisplayed( - ftl::yield( - {NO_ERROR, base::unique_fd(releaseFence->dup())}) - .share()); + ftl::yield(std::move(releaseFence)).share()); } // We've got a list of layers needing fences, that are disjoint with // OutputLayersOrderedByZ. The best we can do is to // supply them with the present fence. for (auto& weakLayer : mReleasedLayers) { - if (auto layer = weakLayer.promote(); layer != nullptr) { - layer->onLayerDisplayed(ftl::yield( - {NO_ERROR, base::unique_fd(frame.presentFence->dup())}) - .share()); + if (const auto layer = weakLayer.promote()) { + layer->onLayerDisplayed(ftl::yield(frame.presentFence).share()); } } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index aaca4fe424..d15b0a7646 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -271,13 +271,16 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te bufferFence.reset(texture->getReadyFence()->dup()); } - auto [status, drawFence] = renderEngine - .drawLayers(displaySettings, layerSettings, texture->get(), - false, std::move(bufferFence)) - .get(); + constexpr bool kUseFramebufferCache = false; - if (status == NO_ERROR) { - mDrawFence = new Fence(drawFence.release()); + auto fenceResult = + toFenceResult(renderEngine + .drawLayers(displaySettings, layerSettings, texture->get(), + kUseFramebufferCache, std::move(bufferFence)) + .get()); + + if (fenceStatus(fenceResult) == NO_ERROR) { + mDrawFence = std::move(fenceResult).value_or(Fence::NO_FENCE); mOutputSpace = outputState.framebufferSpace; mTexture = texture; mTexture->setReadyFence(mDrawFence); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 3a3c91e518..784abeac29 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -3171,9 +3171,9 @@ TEST_F(OutputPostFramebufferTest, releaseFencesAreSentToLayerFE) { mOutput.mState.isEnabled = true; // Create three unique fence instances - sp layer1Fence = new Fence(); - sp layer2Fence = new Fence(); - sp layer3Fence = new Fence(); + sp layer1Fence = sp::make(); + sp layer2Fence = sp::make(); + sp layer3Fence = sp::make(); Output::FrameFences frameFences; frameFences.layerFences.emplace(&mLayer1.hwc2Layer, layer1Fence); @@ -3188,23 +3188,17 @@ TEST_F(OutputPostFramebufferTest, releaseFencesAreSentToLayerFE) { // are passed. This happens to work with the current implementation, but // would not survive certain calls like Fence::merge() which would return a // new instance. - base::unique_fd layer1FD(layer1Fence->dup()); - base::unique_fd layer2FD(layer2Fence->dup()); - base::unique_fd layer3FD(layer3Fence->dup()); EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_)) - .WillOnce([&layer1FD](std::shared_future - futureRenderEngineResult) { - EXPECT_EQ(layer1FD, futureRenderEngineResult.get().drawFence); + .WillOnce([&layer1Fence](std::shared_future futureFenceResult) { + EXPECT_EQ(FenceResult(layer1Fence), futureFenceResult.get()); }); EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_)) - .WillOnce([&layer2FD](std::shared_future - futureRenderEngineResult) { - EXPECT_EQ(layer2FD, futureRenderEngineResult.get().drawFence); + .WillOnce([&layer2Fence](std::shared_future futureFenceResult) { + EXPECT_EQ(FenceResult(layer2Fence), futureFenceResult.get()); }); EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_)) - .WillOnce([&layer3FD](std::shared_future - futureRenderEngineResult) { - EXPECT_EQ(layer3FD, futureRenderEngineResult.get().drawFence); + .WillOnce([&layer3Fence](std::shared_future futureFenceResult) { + EXPECT_EQ(FenceResult(layer3Fence), futureFenceResult.get()); }); mOutput.postFramebuffer(); @@ -3214,15 +3208,11 @@ TEST_F(OutputPostFramebufferTest, releaseFencesIncludeClientTargetAcquireFence) mOutput.mState.isEnabled = true; mOutput.mState.usesClientComposition = true; - sp clientTargetAcquireFence = new Fence(); - sp layer1Fence = new Fence(); - sp layer2Fence = new Fence(); - sp layer3Fence = new Fence(); Output::FrameFences frameFences; - frameFences.clientTargetAcquireFence = clientTargetAcquireFence; - frameFences.layerFences.emplace(&mLayer1.hwc2Layer, layer1Fence); - frameFences.layerFences.emplace(&mLayer2.hwc2Layer, layer2Fence); - frameFences.layerFences.emplace(&mLayer3.hwc2Layer, layer3Fence); + frameFences.clientTargetAcquireFence = sp::make(); + frameFences.layerFences.emplace(&mLayer1.hwc2Layer, sp::make()); + frameFences.layerFences.emplace(&mLayer2.hwc2Layer, sp::make()); + frameFences.layerFences.emplace(&mLayer3.hwc2Layer, sp::make()); EXPECT_CALL(*mRenderSurface, flip()); EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences)); @@ -3256,7 +3246,7 @@ TEST_F(OutputPostFramebufferTest, releasedLayersSentPresentFence) { mOutput.setReleasedLayers(std::move(layers)); // Set up a fake present fence - sp presentFence = new Fence(); + sp presentFence = sp::make(); Output::FrameFences frameFences; frameFences.presentFence = presentFence; @@ -3265,21 +3255,17 @@ TEST_F(OutputPostFramebufferTest, releasedLayersSentPresentFence) { EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted()); // Each released layer should be given the presentFence. - base::unique_fd layerFD(presentFence.get()->dup()); EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_)) - .WillOnce([&layerFD](std::shared_future - futureRenderEngineResult) { - EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence); + .WillOnce([&presentFence](std::shared_future futureFenceResult) { + EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get()); }); EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_)) - .WillOnce([&layerFD](std::shared_future - futureRenderEngineResult) { - EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence); + .WillOnce([&presentFence](std::shared_future futureFenceResult) { + EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get()); }); EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_)) - .WillOnce([&layerFD](std::shared_future - futureRenderEngineResult) { - EXPECT_EQ(layerFD, futureRenderEngineResult.get().drawFence); + .WillOnce([&presentFence](std::shared_future futureFenceResult) { + EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get()); }); mOutput.postFramebuffer(); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index e1eec8b97e..2298f038e9 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -213,8 +213,7 @@ LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp client, * Layer. So, the implementation is done in BufferLayer. When called on a * EffectLayer object, it's essentially a NOP. */ -void Layer::onLayerDisplayed( - std::shared_future /*futureRenderEngineResult*/) {} +void Layer::onLayerDisplayed(std::shared_future) {} void Layer::removeRelativeZ(const std::vector& layersInTree) { if (mDrawingState.zOrderRelativeOf == nullptr) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index ecea74413c..100704369e 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -620,8 +620,7 @@ public: void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override; std::vector prepareClientCompositionList( compositionengine::LayerFE::ClientCompositionTargetSettings&) override; - void onLayerDisplayed( - std::shared_future futureRenderEngineResult) override; + void onLayerDisplayed(std::shared_future) override; void setWasClientComposed(const sp& fence) override { mLastClientCompositionFence = fence; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index e29e6ab05f..2487dbd793 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -355,12 +355,15 @@ void RegionSamplingThread::captureSample() { WRITEABLE); } - auto captureScreenResultFuture = - mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - true /* regionSampling */, false /* grayscale */, nullptr); - auto& captureScreenResult = captureScreenResultFuture.get(); - if (captureScreenResult.drawFence.ok()) { - sync_wait(captureScreenResult.drawFence.get(), -1); + constexpr bool kRegionSampling = true; + constexpr bool kGrayscale = false; + + if (const auto fenceResult = + mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, + kRegionSampling, kGrayscale, nullptr) + .get(); + fenceResult.ok()) { + fenceResult.value()->waitForever(LOG_TAG); } std::vector activeDescriptors; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e72e21ceb3..d8a2696ef0 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -6410,10 +6410,10 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, traverseLayersInLayerStack(layerStack, args.uid, visitor); }; - auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, - reqSize, args.pixelFormat, args.allowProtected, - args.grayscale, captureListener); - return captureResultFuture.get().status; + auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, + args.pixelFormat, args.allowProtected, args.grayscale, + captureListener); + return fenceStatus(future.get()); } status_t SurfaceFlinger::captureDisplay(DisplayId displayId, @@ -6452,11 +6452,14 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId, ALOGE("capture screen must provide a capture listener callback"); return BAD_VALUE; } - auto captureResultFuture = - captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, - ui::PixelFormat::RGBA_8888, false /* allowProtected */, - false /* grayscale */, captureListener); - return captureResultFuture.get().status; + + constexpr bool kAllowProtected = false; + constexpr bool kGrayscale = false; + + auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, + ui::PixelFormat::RGBA_8888, kAllowProtected, kGrayscale, + captureListener); + return fenceStatus(future.get()); } status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, @@ -6568,13 +6571,13 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, return BAD_VALUE; } - auto captureResultFuture = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, - reqSize, args.pixelFormat, args.allowProtected, - args.grayscale, captureListener); - return captureResultFuture.get().status; + auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, + args.pixelFormat, args.allowProtected, args.grayscale, + captureListener); + return fenceStatus(future.get()); } -std::shared_future SurfaceFlinger::captureScreenCommon( +std::shared_future SurfaceFlinger::captureScreenCommon( RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale, const sp& captureListener) { @@ -6584,7 +6587,7 @@ std::shared_future SurfaceFlinger::captureScre ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32 ") that exceeds render target size limit.", bufferSize.getWidth(), bufferSize.getHeight()); - return ftl::yield({BAD_VALUE, base::unique_fd()}).share(); + return ftl::yield(base::unexpected(BAD_VALUE)).share(); } // Loop over all visible layers to see whether there's any protected layer. A protected layer is @@ -6626,7 +6629,7 @@ std::shared_future SurfaceFlinger::captureScre false /* regionSampling */, grayscale, captureListener); } -std::shared_future SurfaceFlinger::captureScreenCommon( +std::shared_future SurfaceFlinger::captureScreenCommon( RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, const std::shared_ptr& buffer, bool regionSampling, bool grayscale, const sp& captureListener) { @@ -6634,59 +6637,53 @@ std::shared_future SurfaceFlinger::captureScre bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission(); - auto scheduleResultFuture = mScheduler->schedule([=, - renderAreaFuture = - std::move(renderAreaFuture)]() mutable - -> std::shared_future< - renderengine::RenderEngineResult> { + auto future = mScheduler->schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable + -> std::shared_future { ScreenCaptureResults captureResults; std::unique_ptr renderArea = renderAreaFuture.get(); if (!renderArea) { ALOGW("Skipping screen capture because of invalid render area."); captureResults.result = NO_MEMORY; captureListener->onScreenCaptureCompleted(captureResults); - return ftl::yield({NO_ERROR, base::unique_fd()}) - .share(); + return ftl::yield(base::unexpected(NO_ERROR)).share(); } - std::shared_future renderEngineResultFuture; - + std::shared_future renderFuture; renderArea->render([&] { - renderEngineResultFuture = - renderScreenImpl(*renderArea, traverseLayers, buffer, - canCaptureBlackoutContent, regionSampling, grayscale, - captureResults); + renderFuture = + renderScreenImpl(*renderArea, traverseLayers, buffer, canCaptureBlackoutContent, + regionSampling, grayscale, captureResults); }); - // spring up a thread to unblock SF main thread and wait for - // RenderEngineResult to be available - if (captureListener != nullptr) { + + if (captureListener) { + // TODO: The future returned by std::async blocks the main thread. Return a chain of + // futures to the Binder thread instead. std::async([=]() mutable { ATRACE_NAME("captureListener is nonnull!"); - auto& [status, drawFence] = renderEngineResultFuture.get(); - captureResults.result = status; - captureResults.fence = new Fence(dup(drawFence)); + auto fenceResult = renderFuture.get(); + // TODO(b/232535621): Change ScreenCaptureResults to store a FenceResult. + captureResults.result = fenceStatus(fenceResult); + captureResults.fence = std::move(fenceResult).value_or(Fence::NO_FENCE); captureListener->onScreenCaptureCompleted(captureResults); }); } - return renderEngineResultFuture; + return renderFuture; }); - // flatten scheduleResultFuture object to single shared_future object - if (captureListener == nullptr) { - std::future captureScreenResultFuture = - ftl::chain(std::move(scheduleResultFuture)) - .then([=](std::shared_future futureObject) - -> renderengine::RenderEngineResult { - auto& [status, drawFence] = futureObject.get(); - return {status, base::unique_fd(dup(drawFence))}; - }); - return captureScreenResultFuture.share(); - } else { - return ftl::yield({NO_ERROR, base::unique_fd()}).share(); + if (captureListener) { + return ftl::yield(base::unexpected(NO_ERROR)).share(); } + + // Flatten nested futures. + std::future chain = + ftl::chain(std::move(future)).then([](std::shared_future future) { + return future.get(); + }); + + return chain.share(); } -std::shared_future SurfaceFlinger::renderScreenImpl( +std::shared_future SurfaceFlinger::renderScreenImpl( const RenderArea& renderArea, TraverseLayersFunction traverseLayers, const std::shared_ptr& buffer, bool canCaptureBlackoutContent, bool regionSampling, bool grayscale, @@ -6705,8 +6702,7 @@ std::shared_future SurfaceFlinger::renderScree // the impetus on WindowManager to not persist them. if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) { ALOGW("FB is protected: PERMISSION_DENIED"); - return ftl::yield({PERMISSION_DENIED, base::unique_fd()}) - .share(); + return ftl::yield(base::unexpected(PERMISSION_DENIED)).share(); } captureResults.buffer = buffer->getBuffer(); @@ -6827,23 +6823,22 @@ std::shared_future SurfaceFlinger::renderScree base::unique_fd bufferFence; getRenderEngine().useProtectedContext(useProtected); - const constexpr bool kUseFramebufferCache = false; - std::future drawLayersResult = - getRenderEngine().drawLayers(clientCompositionDisplay, clientRenderEngineLayers, buffer, - kUseFramebufferCache, std::move(bufferFence)); - - std::shared_future drawLayersResultFuture = - drawLayersResult.share(); // drawLayersResult will be moved to shared one + constexpr bool kUseFramebufferCache = false; + std::future chain = + ftl::chain(getRenderEngine().drawLayers(clientCompositionDisplay, + clientRenderEngineLayers, buffer, + kUseFramebufferCache, std::move(bufferFence))) + .then(&toFenceResult); + const auto future = chain.share(); for (auto* layer : renderedLayers) { - // make a copy of shared_future object for each layer - layer->onLayerDisplayed(drawLayersResultFuture); + layer->onLayerDisplayed(future); } // Always switch back to unprotected context. getRenderEngine().useProtectedContext(false); - return drawLayersResultFuture; + return future; } void SurfaceFlinger::windowInfosReported() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c70e1749ff..dc54ac245b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -49,6 +49,7 @@ #include #include +#include #include #include @@ -867,14 +868,15 @@ private: // Boot animation, on/off animations and screen capture void startBootAnim(); - std::shared_future captureScreenCommon( - RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize, ui::PixelFormat, - bool allowProtected, bool grayscale, const sp&); - std::shared_future captureScreenCommon( + std::shared_future captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, + ui::Size bufferSize, ui::PixelFormat, + bool allowProtected, bool grayscale, + const sp&); + std::shared_future captureScreenCommon( RenderAreaFuture, TraverseLayersFunction, const std::shared_ptr&, bool regionSampling, bool grayscale, const sp&); - std::shared_future renderScreenImpl( + std::shared_future renderScreenImpl( const RenderArea&, TraverseLayersFunction, const std::shared_ptr&, bool canCaptureBlackoutContent, bool regionSampling, bool grayscale, ScreenCaptureResults&) EXCLUDES(mStateLock); diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index e1f348fdba..fa8cffc32a 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -133,10 +133,10 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp& if (surfaceControl) { sp prevFence = nullptr; - for (const auto& futureStruct : handle->previousReleaseFences) { - sp currentFence = sp::make(dup(futureStruct.get().drawFence)); + for (const auto& future : handle->previousReleaseFences) { + sp currentFence = future.get().value_or(Fence::NO_FENCE); if (prevFence == nullptr && currentFence->getStatus() != Fence::Status::Invalid) { - prevFence = currentFence; + prevFence = std::move(currentFence); handle->previousReleaseFence = prevFence; } else if (prevFence != nullptr) { // If both fences are signaled or both are unsignaled, we need to merge @@ -147,7 +147,7 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp& snprintf(fenceName, 32, "%.28s", handle->name.c_str()); sp mergedFence = Fence::merge(fenceName, prevFence, currentFence); if (mergedFence->isValid()) { - handle->previousReleaseFence = mergedFence; + handle->previousReleaseFence = std::move(mergedFence); prevFence = handle->previousReleaseFence; } } else if (currentFence->getStatus() == Fence::Status::Unsignaled) { @@ -158,11 +158,12 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp& // by this point, they will have both signaled and only the timestamp // will be slightly off; any dependencies after this point will // already have been met. - handle->previousReleaseFence = currentFence; + handle->previousReleaseFence = std::move(currentFence); } } } - handle->previousReleaseFences = {}; + handle->previousReleaseFences.clear(); + FrameEventHistoryStats eventStats(handle->frameNumber, handle->gpuCompositionDoneFence->getSnapshot().fence, handle->compositorTiming, handle->refreshStartTime, diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index a68cd87313..b96444dcfb 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -28,8 +28,8 @@ #include #include +#include #include -#include #include namespace android { @@ -46,7 +46,7 @@ public: bool releasePreviousBuffer = false; std::string name; sp previousReleaseFence; - std::vector> previousReleaseFences; + std::vector> previousReleaseFences; std::variant> acquireTimeOrFence = -1; nsecs_t latchTime = -1; uint32_t transformHint = 0; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp index 46d52dd221..bd8081f863 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -117,11 +118,11 @@ void LayerFuzzer::invokeBufferStateLayer() { const CompositorTiming compositor = {mFdp.ConsumeIntegral(), mFdp.ConsumeIntegral(), mFdp.ConsumeIntegral()}; - std::packaged_task renderResult([&] { - return renderengine::RenderEngineResult{mFdp.ConsumeIntegral(), - base::unique_fd(fence->get())}; - }); - layer->onLayerDisplayed(renderResult.get_future()); + + layer->onLayerDisplayed(ftl::yield(fence).share()); + layer->onLayerDisplayed( + ftl::yield(base::unexpected(mFdp.ConsumeIntegral())).share()); + layer->releasePendingBuffer(mFdp.ConsumeIntegral()); layer->finalizeFrameEventHistory(fenceTime, compositor); layer->onPostComposition(nullptr, fenceTime, fenceTime, compositor); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index c541b9291f..bbfedc7685 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -245,15 +245,14 @@ void CompositionTest::captureScreenComposition() { HAL_PIXEL_FORMAT_RGBA_8888, 1, usage); - auto result = mFlinger.renderScreenImpl(*renderArea, traverseLayers, mCaptureScreenBuffer, + auto future = mFlinger.renderScreenImpl(*renderArea, traverseLayers, mCaptureScreenBuffer, forSystem, regionSampling); - EXPECT_TRUE(result.valid()); + ASSERT_TRUE(future.valid()); + const auto fenceResult = future.get(); - auto& [status, drawFence] = result.get(); - - EXPECT_EQ(NO_ERROR, status); - if (drawFence.ok()) { - sync_wait(drawFence.get(), -1); + EXPECT_EQ(NO_ERROR, fenceStatus(fenceResult)); + if (fenceResult.ok()) { + fenceResult.value()->waitForever(LOG_TAG); } LayerCase::cleanup(this); -- cgit v1.2.3-59-g8ed1b From b17c62120b646f378c0b842b3d7fcce8a5540e3e Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Mon, 9 May 2022 09:36:19 -0700 Subject: FTL: Yield futures without overhead ftl::yield, which lifts T to std::future, incurs the cost of allocating, ref counting, and locking the latter's shared state. Consolidate the existing std::future extensions into ftl::Future, and optimize ftl::yield by including static storage for T within. Bug: 232436803 Test: simpleperf (-31% cycles in postFramebuffer) Change-Id: I9a7ca7de17e7af10515de97d2f6a0dfa24e35d7a --- include/ftl/details/future.h | 98 ++++++++++++++ include/ftl/future.h | 146 ++++++++++++--------- libs/ftl/future_test.cpp | 10 +- services/surfaceflinger/BufferQueueLayer.cpp | 2 +- services/surfaceflinger/BufferQueueLayer.h | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 2 +- services/surfaceflinger/BufferStateLayer.h | 2 +- .../include/compositionengine/LayerFE.h | 4 +- .../include/compositionengine/mock/LayerFE.h | 2 +- .../CompositionEngine/tests/MockHWComposer.h | 6 +- .../CompositionEngine/tests/OutputTest.cpp | 12 +- services/surfaceflinger/DisplayHardware/HWC2.cpp | 3 +- services/surfaceflinger/DisplayHardware/HWC2.h | 6 +- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 5 +- .../surfaceflinger/DisplayHardware/HWComposer.h | 6 +- services/surfaceflinger/Layer.cpp | 2 +- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 29 ++-- services/surfaceflinger/SurfaceFlinger.h | 16 +-- .../surfaceflinger/TransactionCallbackInvoker.h | 5 +- .../unittests/mock/DisplayHardware/MockHWC2.h | 2 +- 21 files changed, 240 insertions(+), 122 deletions(-) create mode 100644 include/ftl/details/future.h (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/include/ftl/details/future.h b/include/ftl/details/future.h new file mode 100644 index 0000000000..df1323e8be --- /dev/null +++ b/include/ftl/details/future.h @@ -0,0 +1,98 @@ +/* + * Copyright 2022 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 + +namespace android::ftl { + +template class> +class Future; + +namespace details { + +template +struct future_result { + using type = T; +}; + +template +struct future_result> { + using type = T; +}; + +template +struct future_result> { + using type = T; +}; + +template class FutureImpl> +struct future_result> { + using type = T; +}; + +template +using future_result_t = typename future_result::type; + +struct ValueTag {}; + +template class> +class BaseFuture; + +template +class BaseFuture { + using Impl = std::future; + + public: + Future share() { + if (T* value = std::get_if(&self())) { + return {ValueTag{}, std::move(*value)}; + } + + return std::get(self()).share(); + } + + protected: + T get() { + if (T* value = std::get_if(&self())) { + return std::move(*value); + } + + return std::get(self()).get(); + } + + private: + auto& self() { return static_cast(*this).future_; } +}; + +template +class BaseFuture { + using Impl = std::shared_future; + + protected: + const T& get() const { + if (const T* value = std::get_if(&self())) { + return *value; + } + + return std::get(self()).get(); + } + + private: + const auto& self() const { return static_cast(*this).future_; } +}; + +} // namespace details +} // namespace android::ftl diff --git a/include/ftl/future.h b/include/ftl/future.h index dd6358fa7d..c78f9b76b6 100644 --- a/include/ftl/future.h +++ b/include/ftl/future.h @@ -19,91 +19,115 @@ #include #include #include +#include + +#include namespace android::ftl { -// Creates a future that defers a function call until its result is queried. +// Thin wrapper around FutureImpl (concretely std::future or std::shared_future) with +// extensions for pure values (created via ftl::yield) and continuations. // -// auto future = ftl::defer([](int x) { return x + 1; }, 99); -// assert(future.get() == 100); +// See also SharedFuture shorthand below. // -template -inline auto defer(F&& f, Args&&... args) { - return std::async(std::launch::deferred, std::forward(f), std::forward(args)...); -} +template class FutureImpl = std::future> +class Future final : public details::BaseFuture, T, FutureImpl> { + using Base = details::BaseFuture; -// Creates a future that wraps a value. -// -// auto future = ftl::yield(42); -// assert(future.get() == 42); -// -// auto ptr = std::make_unique('!'); -// auto future = ftl::yield(std::move(ptr)); -// assert(*future.get() == '!'); -// -template -inline std::future yield(T&& v) { - return defer([](T&& v) { return std::forward(v); }, std::forward(v)); -} - -namespace details { - -template -struct future_result { - using type = T; -}; + friend Base; // For BaseFuture<...>::self. + friend details::BaseFuture, T, std::future>; // For BaseFuture<...>::share. -template -struct future_result> { - using type = T; -}; - -template -using future_result_t = typename future_result::type; + public: + // Constructs an invalid future. + Future() : future_(std::in_place_type>) {} -// Attaches a continuation to a future. The continuation is a function that maps T to either R or -// std::future. In the former case, the chain wraps the result in a future as if by ftl::yield. -// -// auto future = ftl::yield(123); -// std::future futures[] = {ftl::yield('a'), ftl::yield('b')}; -// -// std::future chain = -// ftl::chain(std::move(future)) -// .then([](int x) { return static_cast(x % 2); }) -// .then([&futures](std::size_t i) { return std::move(futures[i]); }); -// -// assert(chain.get() == 'b'); -// -template -struct Chain { - // Implicit conversion. - Chain(std::future&& f) : future(std::move(f)) {} - operator std::future&&() && { return std::move(future); } + // Constructs a future from its standard counterpart, implicitly. + Future(FutureImpl&& f) : future_(std::move(f)) {} - T get() && { return future.get(); } + bool valid() const { + return std::holds_alternative(future_) || std::get>(future_).valid(); + } + // Forwarding functions. Base::share is only defined when FutureImpl is std::future, whereas the + // following are defined for either FutureImpl: + using Base::get; + + // Attaches a continuation to the future. The continuation is a function that maps T to either R + // or ftl::Future. In the former case, the chain wraps the result in a future as if by + // ftl::yield. + // + // auto future = ftl::yield(123); + // ftl::Future futures[] = {ftl::yield('a'), ftl::yield('b')}; + // + // auto chain = + // ftl::Future(std::move(future)) + // .then([](int x) { return static_cast(x % 2); }) + // .then([&futures](std::size_t i) { return std::move(futures[i]); }); + // + // assert(chain.get() == 'b'); + // template > - auto then(F&& op) && -> Chain> { + auto then(F&& op) && -> Future> { return defer( [](auto&& f, F&& op) { R r = op(f.get()); - if constexpr (std::is_same_v>) { + if constexpr (std::is_same_v>) { return r; } else { return r.get(); } }, - std::move(future), std::forward(op)); + std::move(*this), std::forward(op)); } - std::future future; -}; + private: + template + friend Future yield(V&&); -} // namespace details + template + friend Future yield(Args&&...); + + template + Future(details::ValueTag, Args&&... args) + : future_(std::in_place_type, std::forward(args)...) {} + + std::variant> future_; +}; template -inline auto chain(std::future&& f) -> details::Chain { - return std::move(f); +using SharedFuture = Future; + +// Deduction guide for implicit conversion. +template class FutureImpl> +Future(FutureImpl&&) -> Future; + +// Creates a future that wraps a value. +// +// auto future = ftl::yield(42); +// assert(future.get() == 42); +// +// auto ptr = std::make_unique('!'); +// auto future = ftl::yield(std::move(ptr)); +// assert(*future.get() == '!'); +// +template +inline Future yield(V&& value) { + return {details::ValueTag{}, std::move(value)}; +} + +template +inline Future yield(Args&&... args) { + return {details::ValueTag{}, std::forward(args)...}; +} + +// Creates a future that defers a function call until its result is queried. +// +// auto future = ftl::defer([](int x) { return x + 1; }, 99); +// assert(future.get() == 100); +// +template +inline auto defer(F&& f, Args&&... args) { + return Future(std::async(std::launch::deferred, std::forward(f), std::forward(args)...)); } } // namespace android::ftl diff --git a/libs/ftl/future_test.cpp b/libs/ftl/future_test.cpp index 9b3e93683f..5a245b681c 100644 --- a/libs/ftl/future_test.cpp +++ b/libs/ftl/future_test.cpp @@ -42,9 +42,9 @@ TEST(Future, Example) { } { auto future = ftl::yield(123); - std::future futures[] = {ftl::yield('a'), ftl::yield('b')}; + ftl::Future futures[] = {ftl::yield('a'), ftl::yield('b')}; - std::future chain = ftl::chain(std::move(future)) + ftl::Future chain = ftl::Future(std::move(future)) .then([](int x) { return static_cast(x % 2); }) .then([&futures](size_t i) { return std::move(futures[i]); }); @@ -71,7 +71,7 @@ TEST(Future, Chain) { return ByteVector{str.begin(), str.end()}; }); - std::packaged_task(ByteVector)> decrement_bytes( + std::packaged_task(ByteVector)> decrement_bytes( [](ByteVector bytes) { return ftl::defer(decrement, std::move(bytes)); }); auto fetch = fetch_string.get_future(); @@ -81,7 +81,7 @@ TEST(Future, Chain) { EXPECT_EQ( "hello, world", - ftl::chain(std::move(fetch)) + ftl::Future(std::move(fetch)) .then([](const char* str) { return std::string(str); }) .then([&](std::string str) { auto append = append_string.get_future(); @@ -93,7 +93,7 @@ TEST(Future, Chain) { decrement_thread = std::thread(std::move(decrement_bytes), std::move(bytes)); return decrement; }) - .then([](std::future bytes) { return bytes; }) + .then([](ftl::Future bytes) { return bytes; }) .then([](const ByteVector& bytes) { return std::string(bytes.begin(), bytes.end()); }) .get()); diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 6a1a38b39c..00b7085c8f 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -48,7 +48,7 @@ BufferQueueLayer::~BufferQueueLayer() { // Interface implementation for Layer // ----------------------------------------------------------------------- -void BufferQueueLayer::onLayerDisplayed(std::shared_future futureFenceResult) { +void BufferQueueLayer::onLayerDisplayed(ftl::SharedFuture futureFenceResult) { const sp releaseFence = futureFenceResult.get().value_or(Fence::NO_FENCE); mConsumer->setReleaseFence(releaseFence); diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 4587b5e27c..60380837d1 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -42,7 +42,7 @@ public: // Implements Layer. const char* getType() const override { return "BufferQueueLayer"; } - void onLayerDisplayed(std::shared_future) override; + void onLayerDisplayed(ftl::SharedFuture) override; // If a buffer was replaced this frame, release the former buffer void releasePendingBuffer(nsecs_t dequeueReadyTime) override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index c88511049b..b424a4ae3a 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -73,7 +73,7 @@ BufferStateLayer::~BufferStateLayer() { // ----------------------------------------------------------------------- // Interface implementation for Layer // ----------------------------------------------------------------------- -void BufferStateLayer::onLayerDisplayed(std::shared_future futureFenceResult) { +void BufferStateLayer::onLayerDisplayed(ftl::SharedFuture futureFenceResult) { // If we are displayed on multiple displays in a single composition cycle then we would // need to do careful tracking to enable the use of the mLastClientCompositionFence. // For example we can only use it if all the displays are client comp, and we need diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index cc510d8c74..bce36d8092 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -39,7 +39,7 @@ public: // Implements Layer. const char* getType() const override { return "BufferStateLayer"; } - void onLayerDisplayed(std::shared_future) override; + void onLayerDisplayed(ftl::SharedFuture) override; void releasePendingBuffer(nsecs_t dequeueReadyTime) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index b7fc62fd21..ec610c1b1d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -16,7 +16,6 @@ #pragma once -#include #include #include #include @@ -33,6 +32,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" +#include #include #include @@ -157,7 +157,7 @@ public: ClientCompositionTargetSettings&) = 0; // Called after the layer is displayed to update the presentation fence - virtual void onLayerDisplayed(std::shared_future) = 0; + virtual void onLayerDisplayed(ftl::SharedFuture) = 0; // Gets some kind of identifier for the layer for debug purposes. virtual const char* getDebugName() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index 871599d2cd..1c5c10f823 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -49,7 +49,7 @@ public: std::vector( compositionengine::LayerFE::ClientCompositionTargetSettings&)); - MOCK_METHOD1(onLayerDisplayed, void(std::shared_future)); + MOCK_METHOD(void, onLayerDisplayed, (ftl::SharedFuture), (override)); MOCK_CONST_METHOD0(getDebugName, const char*()); MOCK_CONST_METHOD0(getSequence, int32_t()); diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index ff2aa15dc9..9b12b08063 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -84,9 +84,9 @@ public: MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t)); MOCK_METHOD4(getDisplayedContentSample, status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*)); - MOCK_METHOD4(setDisplayBrightness, - std::future(PhysicalDisplayId, float, float, - const Hwc2::Composer::DisplayBrightnessOptions&)); + MOCK_METHOD(ftl::Future, setDisplayBrightness, + (PhysicalDisplayId, float, float, const Hwc2::Composer::DisplayBrightnessOptions&), + (override)); MOCK_METHOD2(getDisplayBrightnessSupport, status_t(PhysicalDisplayId, bool*)); MOCK_METHOD2(onHotplug, diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 784abeac29..deaea87ff0 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -3189,15 +3189,15 @@ TEST_F(OutputPostFramebufferTest, releaseFencesAreSentToLayerFE) { // would not survive certain calls like Fence::merge() which would return a // new instance. EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_)) - .WillOnce([&layer1Fence](std::shared_future futureFenceResult) { + .WillOnce([&layer1Fence](ftl::SharedFuture futureFenceResult) { EXPECT_EQ(FenceResult(layer1Fence), futureFenceResult.get()); }); EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_)) - .WillOnce([&layer2Fence](std::shared_future futureFenceResult) { + .WillOnce([&layer2Fence](ftl::SharedFuture futureFenceResult) { EXPECT_EQ(FenceResult(layer2Fence), futureFenceResult.get()); }); EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_)) - .WillOnce([&layer3Fence](std::shared_future futureFenceResult) { + .WillOnce([&layer3Fence](ftl::SharedFuture futureFenceResult) { EXPECT_EQ(FenceResult(layer3Fence), futureFenceResult.get()); }); @@ -3256,15 +3256,15 @@ TEST_F(OutputPostFramebufferTest, releasedLayersSentPresentFence) { // Each released layer should be given the presentFence. EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_)) - .WillOnce([&presentFence](std::shared_future futureFenceResult) { + .WillOnce([&presentFence](ftl::SharedFuture futureFenceResult) { EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get()); }); EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_)) - .WillOnce([&presentFence](std::shared_future futureFenceResult) { + .WillOnce([&presentFence](ftl::SharedFuture futureFenceResult) { EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get()); }); EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_)) - .WillOnce([&presentFence](std::shared_future futureFenceResult) { + .WillOnce([&presentFence](ftl::SharedFuture futureFenceResult) { EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get()); }); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index adf4be3df5..c52e96d146 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -27,7 +27,6 @@ #include "HWC2.h" #include -#include #include #include #include @@ -543,7 +542,7 @@ Error Display::presentOrValidate(nsecs_t expectedPresentTime, uint32_t* outNumTy return error; } -std::future Display::setDisplayBrightness( +ftl::Future Display::setDisplayBrightness( float brightness, float brightnessNits, const Hwc2::Composer::DisplayBrightnessOptions& options) { return ftl::defer([composer = &mComposer, id = mId, brightness, brightnessNits, options] { diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index cca20bd47f..24aef9b73c 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -28,7 +29,6 @@ #include #include -#include #include #include #include @@ -147,7 +147,7 @@ public: uint32_t* outNumRequests, android::sp* outPresentFence, uint32_t* state) = 0; - [[nodiscard]] virtual std::future setDisplayBrightness( + [[nodiscard]] virtual ftl::Future setDisplayBrightness( float brightness, float brightnessNits, const Hwc2::Composer::DisplayBrightnessOptions& options) = 0; [[nodiscard]] virtual hal::Error setActiveConfigWithConstraints( @@ -229,7 +229,7 @@ public: uint32_t* outNumRequests, android::sp* outPresentFence, uint32_t* state) override; - std::future setDisplayBrightness( + ftl::Future setDisplayBrightness( float brightness, float brightnessNits, const Hwc2::Composer::DisplayBrightnessOptions& options) override; hal::Error setActiveConfigWithConstraints(hal::HWConfigId configId, diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 79e4c75393..0da8ecea85 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -720,13 +719,13 @@ status_t HWComposer::getDisplayedContentSample(HalDisplayId displayId, uint64_t return NO_ERROR; } -std::future HWComposer::setDisplayBrightness( +ftl::Future HWComposer::setDisplayBrightness( PhysicalDisplayId displayId, float brightness, float brightnessNits, const Hwc2::Composer::DisplayBrightnessOptions& options) { RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield(BAD_INDEX)); auto& display = mDisplayData[displayId].hwcDisplay; - return ftl::chain(display->setDisplayBrightness(brightness, brightnessNits, options)) + return display->setDisplayBrightness(brightness, brightnessNits, options) .then([displayId](hal::Error error) -> status_t { if (error == hal::Error::UNSUPPORTED) { RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 7dc10eaa7d..4c0ecd8502 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -17,7 +17,6 @@ #pragma once #include -#include #include #include #include @@ -26,6 +25,7 @@ #include #include +#include #include #include @@ -195,7 +195,7 @@ public: DisplayedFrameStats* outStats) = 0; // Sets the brightness of a display. - virtual std::future setDisplayBrightness( + virtual ftl::Future setDisplayBrightness( PhysicalDisplayId, float brightness, float brightnessNits, const Hwc2::Composer::DisplayBrightnessOptions&) = 0; @@ -372,7 +372,7 @@ public: uint64_t maxFrames) override; status_t getDisplayedContentSample(HalDisplayId, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) override; - std::future setDisplayBrightness( + ftl::Future setDisplayBrightness( PhysicalDisplayId, float brightness, float brightnessNits, const Hwc2::Composer::DisplayBrightnessOptions&) override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 2298f038e9..a4f25e2900 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -213,7 +213,7 @@ LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp client, * Layer. So, the implementation is done in BufferLayer. When called on a * EffectLayer object, it's essentially a NOP. */ -void Layer::onLayerDisplayed(std::shared_future) {} +void Layer::onLayerDisplayed(ftl::SharedFuture) {} void Layer::removeRelativeZ(const std::vector& layersInTree) { if (mDrawingState.zOrderRelativeOf == nullptr) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 100704369e..74755106c6 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -620,7 +620,7 @@ public: void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override; std::vector prepareClientCompositionList( compositionengine::LayerFE::ClientCompositionTargetSettings&) override; - void onLayerDisplayed(std::shared_future) override; + void onLayerDisplayed(ftl::SharedFuture) override; void setWasClientComposed(const sp& fence) override { mLastClientCompositionFence = fence; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d8a2696ef0..d333ff85f0 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1693,7 +1693,7 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, } const char* const whence = __func__; - return ftl::chain(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { + return ftl::Future(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) { if (const auto display = getDisplayDeviceLocked(displayToken)) { const bool supportsDisplayBrightnessCommand = getHwComposer().getComposer()->isSupported( @@ -1731,7 +1731,7 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, return ftl::yield(NAME_NOT_FOUND); } })) - .then([](std::future task) { return task; }) + .then([](ftl::Future task) { return task; }) .get(); } @@ -6577,7 +6577,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, return fenceStatus(future.get()); } -std::shared_future SurfaceFlinger::captureScreenCommon( +ftl::SharedFuture SurfaceFlinger::captureScreenCommon( RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale, const sp& captureListener) { @@ -6629,7 +6629,7 @@ std::shared_future SurfaceFlinger::captureScreenCommon( false /* regionSampling */, grayscale, captureListener); } -std::shared_future SurfaceFlinger::captureScreenCommon( +ftl::SharedFuture SurfaceFlinger::captureScreenCommon( RenderAreaFuture renderAreaFuture, TraverseLayersFunction traverseLayers, const std::shared_ptr& buffer, bool regionSampling, bool grayscale, const sp& captureListener) { @@ -6638,7 +6638,7 @@ std::shared_future SurfaceFlinger::captureScreenCommon( bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission(); auto future = mScheduler->schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable - -> std::shared_future { + -> ftl::SharedFuture { ScreenCaptureResults captureResults; std::unique_ptr renderArea = renderAreaFuture.get(); if (!renderArea) { @@ -6648,7 +6648,7 @@ std::shared_future SurfaceFlinger::captureScreenCommon( return ftl::yield(base::unexpected(NO_ERROR)).share(); } - std::shared_future renderFuture; + ftl::SharedFuture renderFuture; renderArea->render([&] { renderFuture = renderScreenImpl(*renderArea, traverseLayers, buffer, canCaptureBlackoutContent, @@ -6675,15 +6675,14 @@ std::shared_future SurfaceFlinger::captureScreenCommon( } // Flatten nested futures. - std::future chain = - ftl::chain(std::move(future)).then([](std::shared_future future) { - return future.get(); - }); + auto chain = ftl::Future(std::move(future)).then([](ftl::SharedFuture future) { + return future; + }); return chain.share(); } -std::shared_future SurfaceFlinger::renderScreenImpl( +ftl::SharedFuture SurfaceFlinger::renderScreenImpl( const RenderArea& renderArea, TraverseLayersFunction traverseLayers, const std::shared_ptr& buffer, bool canCaptureBlackoutContent, bool regionSampling, bool grayscale, @@ -6824,10 +6823,10 @@ std::shared_future SurfaceFlinger::renderScreenImpl( getRenderEngine().useProtectedContext(useProtected); constexpr bool kUseFramebufferCache = false; - std::future chain = - ftl::chain(getRenderEngine().drawLayers(clientCompositionDisplay, - clientRenderEngineLayers, buffer, - kUseFramebufferCache, std::move(bufferFence))) + auto chain = + ftl::Future(getRenderEngine().drawLayers(clientCompositionDisplay, + clientRenderEngineLayers, buffer, + kUseFramebufferCache, std::move(bufferFence))) .then(&toFenceResult); const auto future = chain.share(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index dc54ac245b..52dd418bd2 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -77,7 +78,6 @@ #include #include #include -#include #include #include #include @@ -398,7 +398,7 @@ private: using VsyncModulator = scheduler::VsyncModulator; using TransactionSchedule = scheduler::TransactionSchedule; using TraverseLayersFunction = std::function; - using RenderAreaFuture = std::future>; + using RenderAreaFuture = ftl::Future>; using DumpArgs = Vector; using Dumper = std::function; @@ -868,15 +868,15 @@ private: // Boot animation, on/off animations and screen capture void startBootAnim(); - std::shared_future captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, - ui::Size bufferSize, ui::PixelFormat, - bool allowProtected, bool grayscale, - const sp&); - std::shared_future captureScreenCommon( + ftl::SharedFuture captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, + ui::Size bufferSize, ui::PixelFormat, + bool allowProtected, bool grayscale, + const sp&); + ftl::SharedFuture captureScreenCommon( RenderAreaFuture, TraverseLayersFunction, const std::shared_ptr&, bool regionSampling, bool grayscale, const sp&); - std::shared_future renderScreenImpl( + ftl::SharedFuture renderScreenImpl( const RenderArea&, TraverseLayersFunction, const std::shared_ptr&, bool canCaptureBlackoutContent, bool regionSampling, bool grayscale, ScreenCaptureResults&) EXCLUDES(mStateLock); diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index b96444dcfb..81d79f0777 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -26,9 +25,9 @@ #include #include - #include #include +#include #include #include @@ -46,7 +45,7 @@ public: bool releasePreviousBuffer = false; std::string name; sp previousReleaseFence; - std::vector> previousReleaseFences; + std::vector> previousReleaseFences; std::variant> acquireTimeOrFence = -1; nsecs_t latchTime = -1; uint32_t transformHint = 0; diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h index 3e0d6d304b..07cd15da93 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -80,7 +80,7 @@ public: MOCK_METHOD(hal::Error, presentOrValidate, (nsecs_t, uint32_t *, uint32_t *, android::sp *, uint32_t *), (override)); - MOCK_METHOD(std::future, setDisplayBrightness, + MOCK_METHOD(ftl::Future, setDisplayBrightness, (float, float, const Hwc2::Composer::DisplayBrightnessOptions &), (override)); MOCK_METHOD(hal::Error, setActiveConfigWithConstraints, (hal::HWConfigId, const hal::VsyncPeriodChangeConstraints &, -- cgit v1.2.3-59-g8ed1b From 33da9468354b9b530712d4157298a8e0479cf2e5 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 14 Jun 2022 14:55:57 +0000 Subject: Layer: Guard against Region offset overflows When applying a transform to a Region, if the Region is translated to bounds that overlow the int32_t type, the process crashes. For now, we guard against process crashes by manually applying the offset to the Region and checking for overflows. If we detect an overflow in one of the Rects in a Region, we remove the Rect from the resulting Region. Bug: 234247210 Test: atest libgui_test Change-Id: Icd47539accae2e59a7dbd9c9621201bd040fc402 --- libs/gui/tests/EndToEndNativeInputTest.cpp | 49 ++++++++++++++++++++++++++++++ services/surfaceflinger/Layer.cpp | 34 ++++++++++++++++++++- 2 files changed, 82 insertions(+), 1 deletion(-) (limited to 'services/surfaceflinger/Layer.cpp') diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 262987fd27..c6cdeb7706 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -566,6 +566,55 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) { bgSurface->expectTap(12, 24); } +TEST_F(InputSurfacesTest, touchable_region) { + std::unique_ptr surface = makeSurface(100, 100); + + surface->mInputInfo.touchableRegion.set(Rect{19, 29, 21, 31}); + + surface->showAt(11, 22); + + // A tap within the surface but outside the touchable region should not be sent to the surface. + injectTap(20, 30); + EXPECT_EQ(surface->consumeEvent(200 /*timeoutMs*/), nullptr); + + injectTap(31, 52); + surface->expectTap(20, 30); +} + +TEST_F(InputSurfacesTest, input_respects_touchable_region_offset_overflow) { + std::unique_ptr bgSurface = makeSurface(100, 100); + std::unique_ptr fgSurface = makeSurface(100, 100); + bgSurface->showAt(100, 100); + + // Set the touchable region to the values at the limit of its corresponding type. + // Since the surface is offset from the origin, the touchable region will be transformed into + // display space, which would trigger an overflow or an underflow. Ensure that we are protected + // against such a situation. + fgSurface->mInputInfo.touchableRegion.orSelf(Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX}); + + fgSurface->showAt(100, 100); + + // Expect no crash for overflow. The overflowed touchable region is ignored, so the background + // surface receives touch. + injectTap(112, 124); + bgSurface->expectTap(12, 24); +} + +TEST_F(InputSurfacesTest, input_respects_scaled_touchable_region_overflow) { + std::unique_ptr bgSurface = makeSurface(100, 100); + std::unique_ptr fgSurface = makeSurface(100, 100); + bgSurface->showAt(0, 0); + + fgSurface->mInputInfo.touchableRegion.orSelf(Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX}); + fgSurface->showAt(0, 0); + + fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); }); + + // Expect no crash for overflow. + injectTap(12, 24); + fgSurface->expectTap(6, 12); +} + // Ensure we ignore transparent region when getting screen bounds when positioning input frame. TEST_F(InputSurfacesTest, input_ignores_transparent_region) { std::unique_ptr surface = makeSurface(100, 100); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 6ed4a94f25..be16942d40 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2194,6 +2194,37 @@ Rect Layer::getInputBounds() const { return getCroppedBufferSize(getDrawingState()); } +// Applies the given transform to the region, while protecting against overflows caused by any +// offsets. If applying the offset in the transform to any of the Rects in the region would result +// in an overflow, they are not added to the output Region. +static Region transformTouchableRegionSafely(const ui::Transform& t, const Region& r, + const std::string& debugWindowName) { + // Round the translation using the same rounding strategy used by ui::Transform. + const auto tx = static_cast(t.tx() + 0.5); + const auto ty = static_cast(t.ty() + 0.5); + + ui::Transform transformWithoutOffset = t; + transformWithoutOffset.set(0.f, 0.f); + + const Region transformed = transformWithoutOffset.transform(r); + + // Apply the translation to each of the Rects in the region while discarding any that overflow. + Region ret; + for (const auto& rect : transformed) { + Rect newRect; + if (__builtin_add_overflow(rect.left, tx, &newRect.left) || + __builtin_add_overflow(rect.top, ty, &newRect.top) || + __builtin_add_overflow(rect.right, tx, &newRect.right) || + __builtin_add_overflow(rect.bottom, ty, &newRect.bottom)) { + ALOGE("Applying transform to touchable region of window '%s' resulted in an overflow.", + debugWindowName.c_str()); + continue; + } + ret.orSelf(newRect); + } + return ret; +} + void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDisplay) { Rect tmpBounds = getInputBounds(); if (!tmpBounds.isValid()) { @@ -2256,7 +2287,8 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDi info.transform = inputToDisplay.inverse(); // The touchable region is specified in the input coordinate space. Change it to display space. - info.touchableRegion = inputToDisplay.transform(info.touchableRegion); + info.touchableRegion = + transformTouchableRegionSafely(inputToDisplay, info.touchableRegion, mName); } void Layer::fillTouchOcclusionMode(WindowInfo& info) { -- cgit v1.2.3-59-g8ed1b