Merge "Cache blur shaders only when blur is enabled" into sc-dev
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 818804a..0595322 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -342,7 +342,8 @@
// If the initial top-level restorecon above changed the label, then go
// back and restorecon everything recursively
- if (strcmp(before, after)) {
+ // TODO(b/190567190, b/188141923) Remove recursive fixup of com.google.android.gsf.
+ if (strcmp(before, after) || (path.find("com.google.android.gsf") != std::string::npos)) {
if (existing) {
LOG(DEBUG) << "Detected label change from " << before << " to " << after << " at "
<< path << "; running recursive restorecon";
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 204953c..cc0434d 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -292,8 +292,8 @@
}
}
-static unique_fd create_profile(uid_t uid, const std::string& profile, int32_t flags) {
- unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags, 0600)));
+static unique_fd create_profile(uid_t uid, const std::string& profile, int32_t flags, mode_t mode) {
+ unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags, mode)));
if (fd.get() < 0) {
if (errno != EEXIST) {
PLOG(ERROR) << "Failed to create profile " << profile;
@@ -310,7 +310,7 @@
return fd;
}
-static unique_fd open_profile(uid_t uid, const std::string& profile, int32_t flags) {
+static unique_fd open_profile(uid_t uid, const std::string& profile, int32_t flags, mode_t mode) {
// Do not follow symlinks when opening a profile:
// - primary profiles should not contain symlinks in their paths
// - secondary dex paths should have been already resolved and validated
@@ -320,7 +320,7 @@
// Reference profiles and snapshots are created on the fly; so they might not exist beforehand.
unique_fd fd;
if ((flags & O_CREAT) != 0) {
- fd = create_profile(uid, profile, flags);
+ fd = create_profile(uid, profile, flags, mode);
} else {
fd.reset(TEMP_FAILURE_RETRY(open(profile.c_str(), flags)));
}
@@ -336,6 +336,16 @@
PLOG(ERROR) << "Failed to open profile " << profile;
}
return invalid_unique_fd();
+ } else {
+ // If we just create the file we need to set its mode because on Android
+ // open has a mask that only allows owner access.
+ if ((flags & O_CREAT) != 0) {
+ if (fchmod(fd.get(), mode) != 0) {
+ PLOG(ERROR) << "Could not set mode " << std::hex << mode << std::dec
+ << " on profile" << profile;
+ // Not a terminal failure.
+ }
+ }
}
return fd;
@@ -345,20 +355,29 @@
const std::string& location, bool is_secondary_dex) {
std::string profile = create_current_profile_path(user, package_name, location,
is_secondary_dex);
- return open_profile(uid, profile, O_RDONLY);
+ return open_profile(uid, profile, O_RDONLY, /*mode=*/ 0);
}
static unique_fd open_reference_profile(uid_t uid, const std::string& package_name,
const std::string& location, bool read_write, bool is_secondary_dex) {
std::string profile = create_reference_profile_path(package_name, location, is_secondary_dex);
- return open_profile(uid, profile, read_write ? (O_CREAT | O_RDWR) : O_RDONLY);
+ return open_profile(
+ uid,
+ profile,
+ read_write ? (O_CREAT | O_RDWR) : O_RDONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP); // so that ART can also read it when apps run.
}
static UniqueFile open_reference_profile_as_unique_file(uid_t uid, const std::string& package_name,
const std::string& location, bool read_write, bool is_secondary_dex) {
std::string profile_path = create_reference_profile_path(package_name, location,
is_secondary_dex);
- unique_fd ufd = open_profile(uid, profile_path, read_write ? (O_CREAT | O_RDWR) : O_RDONLY);
+ unique_fd ufd = open_profile(
+ uid,
+ profile_path,
+ read_write ? (O_CREAT | O_RDWR) : O_RDONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP); // so that ART can also read it when apps run.
+
return UniqueFile(ufd.release(), profile_path, [](const std::string& path) {
clear_profile(path);
});
@@ -367,7 +386,7 @@
static unique_fd open_spnashot_profile(uid_t uid, const std::string& package_name,
const std::string& location) {
std::string profile = create_snapshot_profile_path(package_name, location);
- return open_profile(uid, profile, O_CREAT | O_RDWR | O_TRUNC);
+ return open_profile(uid, profile, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
}
static void open_profile_files(uid_t uid, const std::string& package_name,
@@ -2484,7 +2503,7 @@
for (size_t i = 0; i < profiles.size(); ) {
std::vector<unique_fd> profiles_fd;
for (size_t k = 0; k < kAggregationBatchSize && i < profiles.size(); k++, i++) {
- unique_fd fd = open_profile(AID_SYSTEM, profiles[i], O_RDONLY);
+ unique_fd fd = open_profile(AID_SYSTEM, profiles[i], O_RDONLY, /*mode=*/ 0);
if (fd.get() >= 0) {
profiles_fd.push_back(std::move(fd));
}
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index e272025..216347e 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -919,7 +919,7 @@
return;
}
- // Check that the snapshot was created witht he expected acess flags.
+ // Check that the snapshot was created with the expected access flags.
CheckFileAccess(snap_profile_, kSystemUid, kSystemGid, 0600 | S_IFREG);
// The snapshot should be equivalent to the merge of profiles.
@@ -962,8 +962,8 @@
return;
}
- // Check that the snapshot was created witht he expected acess flags.
- CheckFileAccess(ref_profile_, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
+ // Check that the snapshot was created with the expected access flags.
+ CheckFileAccess(ref_profile_, kTestAppUid, kTestAppUid, 0640 | S_IFREG);
// The snapshot should be equivalent to the merge of profiles.
std::string ref_profile_content = ref_profile_ + ".expected";
diff --git a/libs/permission/android/permission/PermissionChecker.cpp b/libs/permission/android/permission/PermissionChecker.cpp
index 008afad..66526f9 100644
--- a/libs/permission/android/permission/PermissionChecker.cpp
+++ b/libs/permission/android/permission/PermissionChecker.cpp
@@ -82,6 +82,14 @@
/*startDataDelivery*/ true, /*fromDatasource*/ true, attributedOpCode);
}
+PermissionChecker::PermissionResult PermissionChecker::checkPermissionForPreflight(
+ const String16& permission, const AttributionSourceState& attributionSource,
+ const String16& message, int32_t attributedOpCode)
+{
+ return checkPermission(permission, attributionSource, message, /*forDataDelivery*/ false,
+ /*startDataDelivery*/ false, /*fromDatasource*/ false, attributedOpCode);
+}
+
PermissionChecker::PermissionResult PermissionChecker::checkPermissionForPreflightFromDatasource(
const String16& permission, const AttributionSourceState& attributionSource,
const String16& message, int32_t attributedOpCode)
diff --git a/libs/permission/include/android/permission/PermissionChecker.h b/libs/permission/include/android/permission/PermissionChecker.h
index 308d794..21515e3 100644
--- a/libs/permission/include/android/permission/PermissionChecker.h
+++ b/libs/permission/include/android/permission/PermissionChecker.h
@@ -101,6 +101,29 @@
* has a given permission and whether the app op that corresponds to this permission
* is allowed. The app ops are not noted/started.
*
+ * NOTE: Use this method only for permission checks at the preflight point where you
+ * will not deliver the permission protected data to clients but schedule permission
+ * data delivery, apps register listeners, etc.
+ *
+ * @param permission The permission to check.
+ * @param attributionSource The attribution chain to check.
+ * @param message A message describing the reason the permission was checked.
+ * @param attributedOpCode The op code towards which to blame the access. If this
+ * is a valid app op the op corresponding to the checked permission (if such)
+ * would only be checked to ensure it is allowed and if that succeeds the
+ * starting would be against the attributed op.
+ * @return The permission check result which is either PERMISSION_GRANTED,
+ * or PERMISSION_SOFT_DENIED or PERMISSION_HARD_DENIED.
+ */
+ PermissionResult checkPermissionForPreflight(
+ const String16& permission, const AttributionSourceState& attributionSource,
+ const String16& message, int32_t attributedOpCode);
+
+ /**
+ * Checks whether a given data access chain described by the given attribution source
+ * has a given permission and whether the app op that corresponds to this permission
+ * is allowed. The app ops are not noted/started.
+ *
* NOTE: The attribution source should be for yourself with its next attribution
* source being the app that would receive the data from you.
*
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index 01c84a9..b3975b0 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -149,6 +149,7 @@
PixelSource{
.solidColor = half3(0.1f, 0.2f, 0.3f),
},
+ .alpha = 0.5,
};
auto layers = std::vector<const LayerSettings*>{&layer};
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 2d80c46..9857fc2 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -36,6 +36,7 @@
#include <SkSurface.h>
#include <android-base/stringprintf.h>
#include <gl/GrGLInterface.h>
+#include <gui/TraceUtils.h>
#include <sync/sync.h>
#include <ui/BlurRegion.h>
#include <ui/DebugUtils.h>
@@ -315,6 +316,7 @@
GrContextOptions options;
options.fDisableDriverCorrectnessWorkarounds = true;
options.fDisableDistanceFieldPaths = true;
+ options.fReducedShaderVariations = true;
options.fPersistentCache = &mSkSLCacheMonitor;
mGrContext = GrDirectContext::MakeGL(glInterface, options);
if (useProtectedContext(true)) {
@@ -506,17 +508,18 @@
return;
}
// We currently don't attempt to map a buffer if the buffer contains protected content
- // or we are using a protected context because GPU resources for protected buffers is
- // much more limited.
+ // because GPU resources for protected buffers is much more limited.
const bool isProtectedBuffer = buffer->getUsage() & GRALLOC_USAGE_PROTECTED;
- if (isProtectedBuffer || mInProtectedContext) {
+ if (isProtectedBuffer) {
return;
}
ATRACE_CALL();
- // If we were to support caching protected buffers then we will need to switch the currently
- // bound context if we are not already using the protected context (and subsequently switch
- // back after the buffer is cached).
+ // If we were to support caching protected buffers then we will need to switch the
+ // currently bound context if we are not already using the protected context (and subsequently
+ // switch back after the buffer is cached). However, for non-protected content we can bind
+ // the texture in either GL context because they are initialized with the same share_context
+ // which allows the texture state to be shared between them.
auto grContext = getActiveGrContext();
auto& cache = mTextureCache;
@@ -550,7 +553,6 @@
if (iter->second == 0) {
mTextureCache.erase(buffer->getId());
- mProtectedTextureCache.erase(buffer->getId());
mGraphicBufferExternalRefs.erase(buffer->getId());
}
}
@@ -702,7 +704,7 @@
validateOutputBufferUsage(buffer->getBuffer());
auto grContext = getActiveGrContext();
- auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache;
+ auto& cache = mTextureCache;
std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef;
if (const auto& it = cache.find(buffer->getBuffer()->getId()); it != cache.end()) {
@@ -792,7 +794,7 @@
}
for (const auto& layer : layers) {
- ATRACE_NAME("DrawLayer");
+ ATRACE_FORMAT("DrawLayer: %s", layer->name.c_str());
if (kPrintLayerSettings) {
std::stringstream ls;
@@ -1445,12 +1447,6 @@
StringAppendF(&result, "Skia's Protected Wrapped Objects:\n");
gpuProtectedReporter.logOutput(result, true);
- StringAppendF(&result, "RenderEngine protected AHB/BackendTexture cache size: %zu\n",
- mProtectedTextureCache.size());
- StringAppendF(&result, "Dumping buffer ids...\n");
- for (const auto& [id, unused] : mProtectedTextureCache) {
- StringAppendF(&result, "- 0x%" PRIx64 "\n", id);
- }
StringAppendF(&result, "\n");
StringAppendF(&result, "RenderEngine runtime effects: %zu\n", mRuntimeEffects.size());
for (const auto& [linearEffect, unused] : mRuntimeEffects) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 97d3b72..758c0f8 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -126,11 +126,9 @@
// Number of external holders of ExternalTexture references, per GraphicBuffer ID.
std::unordered_map<GraphicBufferId, int32_t> mGraphicBufferExternalRefs
GUARDED_BY(mRenderingMutex);
- // Cache of GL textures that we'll store per GraphicBuffer ID, sliced by GPU context.
+ // Cache of GL textures that we'll store per GraphicBuffer ID, shared between GPU contexts.
std::unordered_map<GraphicBufferId, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache
GUARDED_BY(mRenderingMutex);
- std::unordered_map<GraphicBufferId, std::shared_ptr<AutoBackendTexture::LocalRef>>
- mProtectedTextureCache GUARDED_BY(mRenderingMutex);
std::unordered_map<LinearEffect, sk_sp<SkRuntimeEffect>, LinearEffectHasher> mRuntimeEffects;
StretchShaderFactory mStretchShaderFactory;
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 9009ce4..5febd8c 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -48,11 +48,8 @@
}
RenderEngineThreaded::~RenderEngineThreaded() {
- {
- std::lock_guard lock(mThreadMutex);
- mRunning = false;
- mCondition.notify_one();
- }
+ mRunning = false;
+ mCondition.notify_one();
if (mThread.joinable()) {
mThread.join();
@@ -71,21 +68,32 @@
mRenderEngine = factory();
- std::unique_lock<std::mutex> lock(mThreadMutex);
pthread_setname_np(pthread_self(), mThreadName);
{
- std::unique_lock<std::mutex> lock(mInitializedMutex);
+ std::scoped_lock lock(mInitializedMutex);
mIsInitialized = true;
}
mInitializedCondition.notify_all();
while (mRunning) {
- if (!mFunctionCalls.empty()) {
- auto task = mFunctionCalls.front();
- mFunctionCalls.pop();
- task(*mRenderEngine);
+ const auto getNextTask = [this]() -> std::optional<Work> {
+ std::scoped_lock lock(mThreadMutex);
+ if (!mFunctionCalls.empty()) {
+ Work task = mFunctionCalls.front();
+ mFunctionCalls.pop();
+ return std::make_optional<Work>(task);
+ }
+ return std::nullopt;
+ };
+
+ const auto task = getNextTask();
+
+ if (task) {
+ (*task)(*mRenderEngine);
}
+
+ std::unique_lock<std::mutex> lock(mThreadMutex);
mCondition.wait(lock, [this]() REQUIRES(mThreadMutex) {
return !mRunning || !mFunctionCalls.empty();
});
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index eb6098e..b78bf21 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -82,9 +82,10 @@
// Protects the creation and destruction of mThread.
mutable std::mutex mThreadMutex;
std::thread mThread GUARDED_BY(mThreadMutex);
- bool mRunning GUARDED_BY(mThreadMutex) = true;
- mutable std::queue<std::function<void(renderengine::RenderEngine& instance)>> mFunctionCalls
- GUARDED_BY(mThreadMutex);
+ std::atomic<bool> mRunning = true;
+
+ using Work = std::function<void(renderengine::RenderEngine&)>;
+ mutable std::queue<Work> mFunctionCalls GUARDED_BY(mThreadMutex);
mutable std::condition_variable mCondition;
// Used to allow select thread safe methods to be accessed without requiring the
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 9df020d..a1c800e 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -2172,6 +2172,13 @@
return true;
}
+/**
+ * Checks if a sensor should be capped according to HIGH_SAMPLING_RATE_SENSORS
+ * permission.
+ *
+ * This needs to be kept in sync with the list defined on the Java side
+ * in frameworks/base/core/java/android/hardware/SystemSensorManager.java
+ */
bool SensorService::isSensorInCappedSet(int sensorType) {
return (sensorType == SENSOR_TYPE_ACCELEROMETER
|| sensorType == SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 08147ed..d738ccd 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -57,6 +57,7 @@
"src/planner/LayerState.cpp",
"src/planner/Planner.cpp",
"src/planner/Predictor.cpp",
+ "src/planner/TexturePool.cpp",
"src/ClientCompositionRequestCache.cpp",
"src/CompositionEngine.cpp",
"src/Display.cpp",
@@ -107,6 +108,7 @@
"tests/planner/FlattenerTest.cpp",
"tests/planner/LayerStateTest.cpp",
"tests/planner/PredictorTest.cpp",
+ "tests/planner/TexturePoolTest.cpp",
"tests/CompositionEngineTest.cpp",
"tests/DisplayColorProfileTest.cpp",
"tests/DisplayTest.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 2ffd472..244f8ab 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -73,10 +73,11 @@
void writeOutputIndependentGeometryStateToHWC(HWC2::Layer*, const LayerFECompositionState&,
bool skipLayer);
void writeOutputDependentPerFrameStateToHWC(HWC2::Layer*);
- void writeOutputIndependentPerFrameStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeOutputIndependentPerFrameStateToHWC(HWC2::Layer*, const LayerFECompositionState&,
+ bool skipLayer);
void writeSolidColorStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
- void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&, bool skipLayer);
void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition,
bool isPeekingThrough, bool skipLayer);
void detectDisallowedCompositionTypeChange(Hwc2::IComposerClient::Composition from,
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 2c18a60..a4356c5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -19,6 +19,7 @@
#include <compositionengine/Output.h>
#include <compositionengine/ProjectionSpace.h>
#include <compositionengine/impl/planner/LayerState.h>
+#include <compositionengine/impl/planner/TexturePool.h>
#include <renderengine/RenderEngine.h>
#include <chrono>
@@ -64,9 +65,12 @@
size_t getLayerCount() const { return mLayers.size(); }
const Layer& getFirstLayer() const { return mLayers[0]; }
const Rect& getBounds() const { return mBounds; }
+ Rect getTextureBounds() const { return mOutputSpace.content; }
const Region& getVisibleRegion() const { return mVisibleRegion; }
size_t getAge() const { return mAge; }
- const std::shared_ptr<renderengine::ExternalTexture>& getBuffer() const { return mTexture; }
+ std::shared_ptr<renderengine::ExternalTexture> getBuffer() const {
+ return mTexture ? mTexture->get() : nullptr;
+ }
const sp<Fence>& getDrawFence() const { return mDrawFence; }
const ProjectionSpace& getOutputSpace() const { return mOutputSpace; }
ui::Dataspace getOutputDataspace() const { return mOutputDataspace; }
@@ -89,7 +93,7 @@
void setLastUpdate(std::chrono::steady_clock::time_point now) { mLastUpdate = now; }
void append(const CachedSet& other) {
- mTexture = nullptr;
+ mTexture.reset();
mOutputDataspace = ui::Dataspace::UNKNOWN;
mDrawFence = nullptr;
mBlurLayer = nullptr;
@@ -105,7 +109,8 @@
void incrementAge() { ++mAge; }
// Renders the cached set with the supplied output composition state.
- void render(renderengine::RenderEngine& re, const OutputCompositionState& outputState);
+ void render(renderengine::RenderEngine& re, TexturePool& texturePool,
+ const OutputCompositionState& outputState);
void dump(std::string& result) const;
@@ -151,7 +156,9 @@
Region mVisibleRegion;
size_t mAge = 0;
- std::shared_ptr<renderengine::ExternalTexture> mTexture;
+ // TODO(b/190411067): This is a shared pointer only because CachedSets are copied into different
+ // containers in the Flattener. Logically this should have unique ownership otherwise.
+ std::shared_ptr<TexturePool::AutoTexture> mTexture;
sp<Fence> mDrawFence;
ProjectionSpace mOutputSpace;
ui::Dataspace mOutputDataspace;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index ca1d69d..94a169e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -37,16 +37,18 @@
class Flattener {
public:
- Flattener(bool enableHolePunch = false) : mEnableHolePunch(enableHolePunch) {}
+ Flattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch = false);
- void setDisplaySize(ui::Size size) { mDisplaySize = size; }
+ void setDisplaySize(ui::Size size) {
+ mDisplaySize = size;
+ mTexturePool.setDisplaySize(size);
+ }
NonBufferHash flattenLayers(const std::vector<const LayerState*>& layers, NonBufferHash,
std::chrono::steady_clock::time_point now);
// Renders the newest cached sets with the supplied output composition state
- void renderCachedSets(renderengine::RenderEngine& re,
- const OutputCompositionState& outputState);
+ void renderCachedSets(const OutputCompositionState& outputState);
void dump(std::string& result) const;
void dumpLayers(std::string& result) const;
@@ -145,8 +147,11 @@
void buildCachedSets(std::chrono::steady_clock::time_point now);
+ renderengine::RenderEngine& mRenderEngine;
const bool mEnableHolePunch;
+ TexturePool mTexturePool;
+
ui::Size mDisplaySize;
NonBufferHash mCurrentGeometry;
@@ -162,6 +167,7 @@
size_t mCachedSetCreationCount = 0;
size_t mCachedSetCreationCost = 0;
std::unordered_map<size_t, size_t> mInvalidatedCachedSetAges;
+ std::chrono::nanoseconds mActiveLayerTimeout = kActiveLayerTimeout;
static constexpr auto kActiveLayerTimeout = std::chrono::nanoseconds(150ms);
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
index 4365b93..fd1ddfc 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
@@ -41,7 +41,7 @@
// as a more efficient representation of parts of the layer stack.
class Planner {
public:
- Planner();
+ Planner(renderengine::RenderEngine& renderengine);
void setDisplaySize(ui::Size);
@@ -59,8 +59,7 @@
compositionengine::Output::OutputLayersEnumerator<compositionengine::Output>&& layers);
// The planner will call to the Flattener to render any pending cached set
- void renderCachedSets(renderengine::RenderEngine& re,
- const OutputCompositionState& outputState);
+ void renderCachedSets(const OutputCompositionState& outputState);
void dump(const Vector<String16>& args, std::string&);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h
new file mode 100644
index 0000000..fb53ee0
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h
@@ -0,0 +1,102 @@
+/*
+ * 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 <compositionengine/Output.h>
+#include <compositionengine/ProjectionSpace.h>
+#include <compositionengine/impl/planner/LayerState.h>
+#include <renderengine/RenderEngine.h>
+
+#include <renderengine/ExternalTexture.h>
+#include <chrono>
+#include "android-base/macros.h"
+
+namespace android::compositionengine::impl::planner {
+
+// A pool of textures that only manages textures of a single size.
+// While it is possible to define a texture pool supporting variable-sized textures to save on
+// memory, it is a simpler implementation to only manage screen-sized textures. The texture pool is
+// unbounded - there are a minimum number of textures preallocated. Under heavy system load, new
+// textures may be allocated, but only a maximum number of retained once those textures are no
+// longer necessary.
+class TexturePool {
+public:
+ // RAII class helping with managing textures from the texture pool
+ // Textures once they're no longer used should be returned to the pool instead of outright
+ // deleted.
+ class AutoTexture {
+ public:
+ AutoTexture(TexturePool& texturePool,
+ std::shared_ptr<renderengine::ExternalTexture> texture, const sp<Fence>& fence)
+ : mTexturePool(texturePool), mTexture(texture), mFence(fence) {}
+
+ ~AutoTexture() { mTexturePool.returnTexture(std::move(mTexture), mFence); }
+
+ sp<Fence> getReadyFence() { return mFence; }
+
+ void setReadyFence(const sp<Fence>& fence) { mFence = fence; }
+
+ // Disable copying and assigning
+ AutoTexture(const AutoTexture&) = delete;
+ AutoTexture& operator=(const AutoTexture&) = delete;
+
+ // Gets a pointer to the underlying external texture
+ const std::shared_ptr<renderengine::ExternalTexture>& get() const { return mTexture; }
+
+ private:
+ TexturePool& mTexturePool;
+ std::shared_ptr<renderengine::ExternalTexture> mTexture;
+ sp<Fence> mFence;
+ };
+
+ TexturePool(renderengine::RenderEngine& renderEngine) : mRenderEngine(renderEngine) {}
+
+ virtual ~TexturePool() = default;
+
+ // Sets the display size for the texture pool.
+ // This will trigger a reallocation for all remaining textures in the pool.
+ // setDisplaySize must be called for the texture pool to be used.
+ void setDisplaySize(ui::Size size);
+
+ // Borrows a new texture from the pool.
+ // If the pool is currently starved of textures, then a new texture is generated.
+ // When the AutoTexture object is destroyed, the scratch texture is automatically returned
+ // to the pool.
+ std::shared_ptr<AutoTexture> borrowTexture();
+
+protected:
+ // Proteted visibility so that they can be used for testing
+ const static constexpr size_t kMinPoolSize = 3;
+ const static constexpr size_t kMaxPoolSize = 4;
+
+ struct Entry {
+ std::shared_ptr<renderengine::ExternalTexture> texture;
+ sp<Fence> fence;
+ };
+
+ std::deque<Entry> mPool;
+
+private:
+ std::shared_ptr<renderengine::ExternalTexture> genTexture();
+ // Returns a previously borrowed texture to the pool.
+ void returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture,
+ const sp<Fence>& fence);
+ renderengine::RenderEngine& mRenderEngine;
+ ui::Size mSize;
+};
+
+} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index e9a8b91..cd2f742 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -129,7 +129,7 @@
}
if (enabled) {
- mPlanner = std::make_unique<planner::Planner>();
+ mPlanner = std::make_unique<planner::Planner>(getCompositionEngine().getRenderEngine());
if (mRenderSurface) {
mPlanner->setDisplaySize(mRenderSurface->getSize());
}
@@ -1314,7 +1314,7 @@
void Output::renderCachedSets() {
if (mPlanner) {
- mPlanner->renderCachedSets(getCompositionEngine().getRenderEngine(), getState());
+ mPlanner->renderCachedSets(getState());
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index cd14327..e4e46a7 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -349,7 +349,7 @@
}
writeOutputDependentPerFrameStateToHWC(hwcLayer.get());
- writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), *outputIndependentState);
+ writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), *outputIndependentState, skipLayer);
writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough,
skipLayer);
@@ -471,7 +471,8 @@
}
void OutputLayer::writeOutputIndependentPerFrameStateToHWC(
- HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) {
+ HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState,
+ bool skipLayer) {
switch (auto error = hwcLayer->setColorTransform(outputIndependentState.colorTransform)) {
case hal::Error::NONE:
break;
@@ -504,7 +505,7 @@
break;
case hal::Composition::CURSOR:
case hal::Composition::DEVICE:
- writeBufferStateToHWC(hwcLayer, outputIndependentState);
+ writeBufferStateToHWC(hwcLayer, outputIndependentState, skipLayer);
break;
case hal::Composition::INVALID:
case hal::Composition::CLIENT:
@@ -541,7 +542,8 @@
}
void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer,
- const LayerFECompositionState& outputIndependentState) {
+ const LayerFECompositionState& outputIndependentState,
+ bool skipLayer) {
auto supportedPerFrameMetadata =
getOutput().getDisplayColorProfile()->getSupportedPerFrameMetadata();
if (auto error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata,
@@ -554,7 +556,7 @@
sp<GraphicBuffer> buffer = outputIndependentState.buffer;
sp<Fence> acquireFence = outputIndependentState.acquireFence;
int slot = outputIndependentState.bufferSlot;
- if (getState().overrideInfo.buffer != nullptr) {
+ if (getState().overrideInfo.buffer != nullptr && !skipLayer) {
buffer = getState().overrideInfo.buffer->getBuffer();
acquireFence = getState().overrideInfo.acquireFence;
slot = HwcBufferCache::FLATTENER_CACHING_SLOT;
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index dcfb05d..68b6231 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -134,7 +134,7 @@
}
bool CachedSet::hasReadyBuffer() const {
- return mTexture != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled;
+ return mTexture && mDrawFence->getStatus() == Fence::Status::Signaled;
}
std::vector<CachedSet> CachedSet::decompose() const {
@@ -156,7 +156,7 @@
}
}
-void CachedSet::render(renderengine::RenderEngine& renderEngine,
+void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& texturePool,
const OutputCompositionState& outputState) {
ATRACE_CALL();
const Rect& viewport = outputState.layerStackSpace.content;
@@ -165,10 +165,7 @@
ui::Transform::toRotationFlags(outputState.framebufferSpace.orientation);
renderengine::DisplaySettings displaySettings{
- .physicalDisplay = Rect(-mBounds.left + outputState.framebufferSpace.content.left,
- -mBounds.top + outputState.framebufferSpace.content.top,
- -mBounds.left + outputState.framebufferSpace.content.right,
- -mBounds.top + outputState.framebufferSpace.content.bottom),
+ .physicalDisplay = outputState.framebufferSpace.content,
.clip = viewport,
.outputDataspace = outputDataspace,
.orientation = orientation,
@@ -255,30 +252,33 @@
layerSettingsPointers.emplace_back(&highlight);
}
- const uint64_t usageFlags = GraphicBuffer::USAGE_HW_RENDER | GraphicBuffer::USAGE_HW_COMPOSER |
- GraphicBuffer::USAGE_HW_TEXTURE;
- sp<GraphicBuffer> buffer = new GraphicBuffer(static_cast<uint32_t>(mBounds.getWidth()),
- static_cast<uint32_t>(mBounds.getHeight()),
- HAL_PIXEL_FORMAT_RGBA_8888, 1, usageFlags);
- const auto texture = std::make_shared<
- renderengine::ExternalTexture>(buffer, renderEngine,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
- LOG_ALWAYS_FATAL_IF(buffer->initCheck() != OK);
- base::unique_fd drawFence;
+ auto texture = texturePool.borrowTexture();
+ LOG_ALWAYS_FATAL_IF(texture->get()->getBuffer()->initCheck() != OK);
- status_t result = renderEngine.drawLayers(displaySettings, layerSettingsPointers, texture,
- false, base::unique_fd(), &drawFence);
+ base::unique_fd bufferFence;
+ if (texture->getReadyFence()) {
+ // Bail out if the buffer is not ready, because there is some pending GPU work left.
+ if (texture->getReadyFence()->getStatus() != Fence::Status::Signaled) {
+ return;
+ }
+ bufferFence.reset(texture->getReadyFence()->dup());
+ }
+
+ base::unique_fd drawFence;
+ status_t result =
+ renderEngine.drawLayers(displaySettings, layerSettingsPointers, texture->get(), false,
+ std::move(bufferFence), &drawFence);
if (result == NO_ERROR) {
mDrawFence = new Fence(drawFence.release());
mOutputSpace = outputState.framebufferSpace;
- mTexture = std::move(texture);
+ mTexture = texture;
+ mTexture->setReadyFence(mDrawFence);
mOutputSpace.orientation = outputState.framebufferSpace.orientation;
mOutputDataspace = outputDataspace;
mOrientation = orientation;
} else {
- mTexture = nullptr;
+ mTexture.reset();
}
}
@@ -294,6 +294,12 @@
return false;
}
+ // Do not use a hole punch with an HDR layer; this should be done in client
+ // composition to properly mix HDR with SDR.
+ if (hasHdrLayers()) {
+ return false;
+ }
+
const auto& layerFE = mLayers[0].getState()->getOutputLayer()->getLayerFE();
if (layerFE.getCompositionState()->forceClientComposition) {
return false;
@@ -363,7 +369,7 @@
base::StringAppendF(&result, " + Fingerprint %016zx, last update %sago, age %zd\n",
mFingerprint, durationString(lastUpdate).c_str(), mAge);
{
- const auto b = mTexture ? mTexture->getBuffer().get() : nullptr;
+ const auto b = mTexture ? mTexture->get()->getBuffer().get() : nullptr;
base::StringAppendF(&result, " Override buffer: %p\n", b);
}
base::StringAppendF(&result, " HolePunchLayer: %p\n", mHolePunchLayer);
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 233b5f2..192c411 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -19,6 +19,7 @@
// #define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <android-base/properties.h>
#include <compositionengine/impl/planner/Flattener.h>
#include <compositionengine/impl/planner/LayerState.h>
@@ -59,6 +60,17 @@
} // namespace
+Flattener::Flattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch)
+ : mRenderEngine(renderEngine),
+ mEnableHolePunch(enableHolePunch),
+ mTexturePool(mRenderEngine) {
+ const int timeoutInMs =
+ base::GetIntProperty(std::string("debug.sf.layer_caching_active_layer_timeout_ms"), 0);
+ if (timeoutInMs != 0) {
+ mActiveLayerTimeout = std::chrono::milliseconds(timeoutInMs);
+ }
+}
+
NonBufferHash Flattener::flattenLayers(const std::vector<const LayerState*>& layers,
NonBufferHash hash, time_point now) {
ATRACE_CALL();
@@ -93,14 +105,13 @@
return hash;
}
-void Flattener::renderCachedSets(renderengine::RenderEngine& renderEngine,
- const OutputCompositionState& outputState) {
+void Flattener::renderCachedSets(const OutputCompositionState& outputState) {
ATRACE_CALL();
if (!mNewCachedSet || mNewCachedSet->hasRenderedBuffer()) {
return;
}
- mNewCachedSet->render(renderEngine, outputState);
+ mNewCachedSet->render(mRenderEngine, mTexturePool, outputState);
}
void Flattener::dumpLayers(std::string& result) const {
@@ -276,7 +287,7 @@
state.overrideInfo = {
.buffer = mNewCachedSet->getBuffer(),
.acquireFence = mNewCachedSet->getDrawFence(),
- .displayFrame = mNewCachedSet->getBounds(),
+ .displayFrame = mNewCachedSet->getTextureBounds(),
.dataspace = mNewCachedSet->getOutputDataspace(),
.displaySpace = mNewCachedSet->getOutputSpace(),
.damageRegion = Region::INVALID_REGION,
@@ -316,7 +327,7 @@
state.overrideInfo = {
.buffer = currentLayerIter->getBuffer(),
.acquireFence = currentLayerIter->getDrawFence(),
- .displayFrame = currentLayerIter->getBounds(),
+ .displayFrame = currentLayerIter->getTextureBounds(),
.dataspace = currentLayerIter->getOutputDataspace(),
.displaySpace = currentLayerIter->getOutputSpace(),
.damageRegion = Region(),
@@ -370,7 +381,7 @@
bool runHasFirstLayer = false;
for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) {
- const bool layerIsInactive = now - currentSet->getLastUpdate() > kActiveLayerTimeout;
+ const bool layerIsInactive = now - currentSet->getLastUpdate() > mActiveLayerTimeout;
const bool layerHasBlur = currentSet->hasBlurBehind();
if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) &&
!currentSet->hasHdrLayers() && !currentSet->hasProtectedLayers()) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index 297c0b2..711a634 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -29,12 +29,13 @@
namespace android::compositionengine::impl::planner {
-Planner::Planner()
+Planner::Planner(renderengine::RenderEngine& renderEngine)
// Implicitly, layer caching must also be enabled for the hole punch or
// predictor to have any effect.
// E.g., setprop debug.sf.enable_layer_caching 1, or
// adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>]
- : mFlattener(base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), true)) {
+ : mFlattener(renderEngine,
+ base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), true)) {
mPredictorEnabled =
base::GetBoolProperty(std::string("debug.sf.enable_planner_prediction"), false);
}
@@ -160,10 +161,9 @@
finalPlan);
}
-void Planner::renderCachedSets(renderengine::RenderEngine& renderEngine,
- const OutputCompositionState& outputState) {
+void Planner::renderCachedSets(const OutputCompositionState& outputState) {
ATRACE_CALL();
- mFlattener.renderCachedSets(renderEngine, outputState);
+ mFlattener.renderCachedSets(outputState);
}
void Planner::dump(const Vector<String16>& args, std::string& result) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
new file mode 100644
index 0000000..e3772a2
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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_NDEBUG 0
+
+#undef LOG_TAG
+#define LOG_TAG "Planner"
+
+#include <compositionengine/impl/planner/TexturePool.h>
+#include <utils/Log.h>
+
+namespace android::compositionengine::impl::planner {
+
+void TexturePool::setDisplaySize(ui::Size size) {
+ if (mSize == size) {
+ return;
+ }
+ mSize = size;
+ mPool.clear();
+ mPool.resize(kMinPoolSize);
+ std::generate_n(mPool.begin(), kMinPoolSize, [&]() { return Entry{genTexture(), nullptr}; });
+}
+
+std::shared_ptr<TexturePool::AutoTexture> TexturePool::borrowTexture() {
+ if (mPool.empty()) {
+ return std::make_shared<AutoTexture>(*this, genTexture(), nullptr);
+ }
+
+ const auto entry = mPool.front();
+ mPool.pop_front();
+ return std::make_shared<AutoTexture>(*this, entry.texture, entry.fence);
+}
+
+void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture,
+ const sp<Fence>& fence) {
+ // Drop the texture on the floor if the pool is no longer tracking textures of the same size.
+ if (static_cast<int32_t>(texture->getBuffer()->getWidth()) != mSize.getWidth() ||
+ static_cast<int32_t>(texture->getBuffer()->getHeight()) != mSize.getHeight()) {
+ ALOGV("Deallocating texture from Planner's pool - display size changed (previous: (%dx%d), "
+ "current: (%dx%d))",
+ texture->getBuffer()->getWidth(), texture->getBuffer()->getHeight(), mSize.getWidth(),
+ mSize.getHeight());
+ return;
+ }
+
+ // Also ensure the pool does not grow beyond a maximum size.
+ if (mPool.size() == kMaxPoolSize) {
+ ALOGD("Deallocating texture from Planner's pool - max size [%" PRIu64 "] reached",
+ static_cast<uint64_t>(kMaxPoolSize));
+ return;
+ }
+
+ mPool.push_back({std::move(texture), fence});
+}
+
+std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture() {
+ LOG_ALWAYS_FATAL_IF(!mSize.isValid(), "Attempted to generate texture with invalid size");
+ return std::make_shared<
+ renderengine::ExternalTexture>(sp<GraphicBuffer>::
+ make(mSize.getWidth(), mSize.getHeight(),
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GraphicBuffer::USAGE_HW_RENDER |
+ GraphicBuffer::USAGE_HW_COMPOSER |
+ GraphicBuffer::USAGE_HW_TEXTURE,
+ "Planner"),
+ mRenderEngine,
+ renderengine::ExternalTexture::Usage::READABLE |
+ renderengine::ExternalTexture::Usage::WRITEABLE);
+}
+
+} // namespace android::compositionengine::impl::planner
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 5bd1216..e9ecf3e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -699,6 +699,7 @@
Hwc2::IComposerClient::BlendMode::PREMULTIPLIED;
static constexpr float kAlpha = 51.f;
static constexpr float kOverrideAlpha = 1.f;
+ static constexpr float kSkipAlpha = 0.f;
static constexpr ui::Dataspace kDataspace = static_cast<ui::Dataspace>(71);
static constexpr ui::Dataspace kOverrideDataspace = static_cast<ui::Dataspace>(72);
static constexpr int kSupportedPerFrameMetadata = 101;
@@ -1055,6 +1056,22 @@
/*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
+TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerDoesNotSendBuffer) {
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+ includeOverrideInfo();
+
+ expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
+ kOverrideBlendMode, kSkipAlpha);
+ expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
+ kOverrideSurfaceDamage);
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
+}
+
TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) {
mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
includeOverrideInfo();
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 52e0428..c381081 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -143,6 +143,7 @@
mOutput->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
mOutput->editState().displaySpace.bounds = kDefaultDisplaySize;
+ EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
}
void injectOutputLayer(InjectedLayer& layer) {
@@ -156,6 +157,7 @@
static const Rect kDefaultDisplaySize;
StrictMock<mock::CompositionEngine> mCompositionEngine;
+ StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
std::shared_ptr<Output> mOutput = createOutput(mCompositionEngine);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 8eeb0bf..4a76a95 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -40,6 +40,7 @@
using impl::planner::CachedSet;
using impl::planner::LayerState;
using impl::planner::LayerStateField;
+using impl::planner::TexturePool;
namespace {
@@ -50,6 +51,7 @@
return expectedBlurSetting == arg.blurSetting;
}
+static const ui::Size kOutputSize = ui::Size(1, 1);
class CachedSetTest : public testing::Test {
public:
@@ -76,9 +78,11 @@
impl::OutputCompositionState mOutputState;
android::renderengine::mock::RenderEngine mRenderEngine;
+ TexturePool mTexturePool = TexturePool(mRenderEngine);
};
void CachedSetTest::SetUp() {
+ mTexturePool.setDisplaySize(kOutputSize);
for (size_t i = 0; i < kNumLayers; i++) {
auto testLayer = std::make_unique<TestLayer>();
auto pos = static_cast<int32_t>(i);
@@ -319,7 +323,7 @@
const std::vector<const renderengine::LayerSettings*>& layers,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
base::unique_fd&&, base::unique_fd*) -> size_t {
- EXPECT_EQ(Rect(-1, -1, 9, 4), displaySettings.physicalDisplay);
+ EXPECT_EQ(mOutputState.framebufferSpace.content, displaySettings.physicalDisplay);
EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
displaySettings.orientation);
@@ -333,10 +337,11 @@
EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
expectReadyBuffer(cachedSet);
EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
+ EXPECT_EQ(mOutputState.framebufferSpace.content, cachedSet.getTextureBounds());
// Now check that appending a new cached set properly cleans up RenderEngine resources.
CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
@@ -367,7 +372,7 @@
const std::vector<const renderengine::LayerSettings*>& layers,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
base::unique_fd&&, base::unique_fd*) -> size_t {
- EXPECT_EQ(Rect(1, 2, 9, 4), displaySettings.physicalDisplay);
+ EXPECT_EQ(mOutputState.framebufferSpace.content, displaySettings.physicalDisplay);
EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
displaySettings.orientation);
@@ -381,7 +386,7 @@
EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
expectReadyBuffer(cachedSet);
EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
@@ -424,6 +429,20 @@
EXPECT_FALSE(cachedSet.requiresHolePunch());
}
+TEST_F(CachedSetTest, holePunch_requiresNonHdr) {
+ mTestLayers[0]->outputLayerCompositionState.dataspace = ui::Dataspace::BT2020_PQ;
+ mTestLayers[0]->layerState->update(&mTestLayers[0]->outputLayer);
+
+ CachedSet::Layer& layer = *mTestLayers[0]->cachedSetLayer.get();
+ mTestLayers[0]->layerFECompositionState.buffer = sp<GraphicBuffer>::make();
+ sp<mock::LayerFE> layerFE = mTestLayers[0]->layerFE;
+
+ CachedSet cachedSet(layer);
+ EXPECT_CALL(*layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
+
+ EXPECT_FALSE(cachedSet.requiresHolePunch());
+}
+
TEST_F(CachedSetTest, requiresHolePunch) {
CachedSet::Layer& layer = *mTestLayers[0]->cachedSetLayer.get();
mTestLayers[0]->layerFECompositionState.buffer = sp<GraphicBuffer>::make();
@@ -554,7 +573,7 @@
};
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
}
TEST_F(CachedSetTest, addHolePunch_noBuffer) {
@@ -604,7 +623,7 @@
};
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
}
TEST_F(CachedSetTest, append_removesHolePunch) {
@@ -741,7 +760,7 @@
};
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine, mOutputState);
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
}
} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 8b03964..e176c98 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -46,13 +46,14 @@
class TestableFlattener : public Flattener {
public:
- TestableFlattener(bool enableHolePunch) : Flattener(enableHolePunch) {}
+ TestableFlattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch)
+ : Flattener(renderEngine, enableHolePunch) {}
const std::optional<CachedSet>& getNewCachedSetForTesting() const { return mNewCachedSet; }
};
class FlattenerTest : public testing::Test {
public:
- FlattenerTest() : mFlattener(std::make_unique<TestableFlattener>(true)) {}
+ FlattenerTest() : mFlattener(std::make_unique<TestableFlattener>(mRenderEngine, true)) {}
void SetUp() override;
protected:
@@ -60,7 +61,7 @@
void initializeFlattener(const std::vector<const LayerState*>& layers);
void expectAllLayersFlattened(const std::vector<const LayerState*>& layers);
- // mRenderEngine may be held as a pointer to mFlattener, so mFlattener must be destroyed first.
+ // mRenderEngine is held as a reference in mFlattener, so mFlattener must be destroyed first.
renderengine::mock::RenderEngine mRenderEngine;
std::unique_ptr<TestableFlattener> mFlattener;
@@ -84,6 +85,7 @@
};
void FlattenerTest::SetUp() {
+ mFlattener->setDisplaySize({1, 1});
for (size_t i = 0; i < kNumLayers; i++) {
auto testLayer = std::make_unique<TestLayer>();
auto pos = static_cast<int32_t>(i);
@@ -146,13 +148,13 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
// same geometry, update the internal layer stack
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
}
void FlattenerTest::expectAllLayersFlattened(const std::vector<const LayerState*>& layers) {
@@ -162,7 +164,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -172,7 +174,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
const auto buffer = layers[0]->getOutputLayer()->getState().overrideInfo.buffer;
EXPECT_NE(nullptr, buffer);
@@ -207,7 +209,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
}
TEST_F(FlattenerTest, flattenLayers_basicFlatten) {
@@ -253,7 +255,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -358,7 +360,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -395,7 +397,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -404,7 +406,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_NE(nullptr, overrideBuffer2);
@@ -417,7 +419,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_NE(nullptr, overrideBuffer2);
@@ -426,7 +428,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -468,7 +470,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -482,7 +484,7 @@
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
mOutputState.framebufferSpace.orientation = ui::ROTATION_90;
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -495,7 +497,7 @@
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
mOutputState.framebufferSpace.orientation = ui::ROTATION_180;
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -510,7 +512,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -522,7 +524,7 @@
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
mOutputState.framebufferSpace.orientation = ui::ROTATION_270;
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -561,7 +563,7 @@
// This will render a CachedSet.
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
// We've rendered a CachedSet, but we haven't merged it in.
EXPECT_EQ(nullptr, overrideBuffer1);
@@ -574,7 +576,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -623,7 +625,7 @@
// This will render a CachedSet.
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
// We've rendered a CachedSet, but we haven't merged it in.
EXPECT_EQ(nullptr, overrideBuffer1);
@@ -636,7 +638,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -680,7 +682,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -690,7 +692,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
EXPECT_EQ(nullptr, overrideBuffer3);
@@ -724,7 +726,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -735,7 +737,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
}
@@ -776,7 +778,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -786,7 +788,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, blurOverrideBuffer);
EXPECT_NE(nullptr, overrideBuffer3);
@@ -823,7 +825,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
const auto& cachedSet = mFlattener->getNewCachedSetForTesting();
ASSERT_NE(std::nullopt, cachedSet);
@@ -837,7 +839,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer2, overrideBuffer1);
EXPECT_EQ(nullptr, blurOverrideBuffer);
@@ -864,7 +866,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -872,12 +874,12 @@
// Simulate attempting to render prior to merging the new cached set with the layer stack.
// Here we should not try to re-render.
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
// We provide the override buffer now that it's rendered
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine, mOutputState);
+ mFlattener->renderCachedSets(mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer2, overrideBuffer1);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp
new file mode 100644
index 0000000..b802e51
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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 "TexturePoolTest"
+
+#include <compositionengine/impl/planner/TexturePool.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <renderengine/mock/RenderEngine.h>
+
+namespace android::compositionengine::impl::planner {
+namespace {
+
+const ui::Size kDisplaySize(1, 1);
+const ui::Size kDisplaySizeTwo(2, 2);
+
+class TestableTexturePool : public TexturePool {
+public:
+ TestableTexturePool(renderengine::RenderEngine& renderEngine) : TexturePool(renderEngine) {}
+
+ size_t getMinPoolSize() const { return kMinPoolSize; }
+ size_t getMaxPoolSize() const { return kMaxPoolSize; }
+ size_t getPoolSize() const { return mPool.size(); }
+};
+
+struct TexturePoolTest : public testing::Test {
+ TexturePoolTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ mTexturePool.setDisplaySize(kDisplaySize);
+ }
+
+ ~TexturePoolTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ renderengine::mock::RenderEngine mRenderEngine;
+ TestableTexturePool mTexturePool = TestableTexturePool(mRenderEngine);
+};
+
+TEST_F(TexturePoolTest, preallocatesMinPool) {
+ EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize());
+}
+
+TEST_F(TexturePoolTest, doesNotAllocateBeyondMinPool) {
+ for (size_t i = 0; i < mTexturePool.getMinPoolSize() + 1; i++) {
+ auto texture = mTexturePool.borrowTexture();
+ }
+
+ EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize());
+}
+
+TEST_F(TexturePoolTest, cyclesUpToMaxPoolSize) {
+ std::unordered_set<uint64_t> bufferIds;
+ std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures;
+ for (size_t i = 0; i < mTexturePool.getMaxPoolSize(); i++) {
+ textures.emplace_back(mTexturePool.borrowTexture());
+ bufferIds.insert(textures.back()->get()->getBuffer()->getId());
+ }
+
+ EXPECT_EQ(mTexturePool.getMaxPoolSize(), bufferIds.size());
+
+ for (size_t i = 0; i < 3; i++) {
+ textures.pop_front();
+ textures.emplace_back(mTexturePool.borrowTexture());
+ bufferIds.insert(textures.back()->get()->getBuffer()->getId());
+ }
+
+ EXPECT_EQ(mTexturePool.getMaxPoolSize(), bufferIds.size());
+}
+
+TEST_F(TexturePoolTest, goesPastMaxSizeAndRebounds) {
+ std::unordered_set<uint64_t> bufferIds;
+ std::vector<std::shared_ptr<TexturePool::AutoTexture>> textures;
+ for (size_t i = 0; i < mTexturePool.getMaxPoolSize() + 2; i++) {
+ textures.emplace_back(mTexturePool.borrowTexture());
+ bufferIds.insert(textures.back()->get()->getBuffer()->getId());
+ }
+
+ EXPECT_EQ(mTexturePool.getMaxPoolSize() + 2, bufferIds.size());
+
+ // Return the textures to the pool.
+ // Now when we cycle through the pool it's again bounded by max textures.
+ textures.clear();
+
+ std::unordered_set<uint64_t> newBufferIds;
+ for (size_t i = 0; i < 2 * mTexturePool.getMaxPoolSize(); i++) {
+ auto texture = mTexturePool.borrowTexture();
+ newBufferIds.insert(texture->get()->getBuffer()->getId());
+ }
+
+ EXPECT_EQ(mTexturePool.getMaxPoolSize(), newBufferIds.size());
+}
+
+TEST_F(TexturePoolTest, reallocatesWhenDisplaySizeChanges) {
+ auto texture = mTexturePool.borrowTexture();
+
+ EXPECT_EQ(kDisplaySize.getWidth(),
+ static_cast<int32_t>(texture->get()->getBuffer()->getWidth()));
+ EXPECT_EQ(kDisplaySize.getHeight(),
+ static_cast<int32_t>(texture->get()->getBuffer()->getHeight()));
+ mTexturePool.setDisplaySize(kDisplaySizeTwo);
+
+ EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize());
+ texture.reset();
+ // When the texture is returned to the pool, the pool now destroys it.
+ EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize());
+
+ texture = mTexturePool.borrowTexture();
+ EXPECT_EQ(kDisplaySizeTwo.getWidth(),
+ static_cast<int32_t>(texture->get()->getBuffer()->getWidth()));
+ EXPECT_EQ(kDisplaySizeTwo.getHeight(),
+ static_cast<int32_t>(texture->get()->getBuffer()->getHeight()));
+}
+
+} // namespace
+} // namespace android::compositionengine::impl::planner
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index 1010aa5..f15a963 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -95,7 +95,10 @@
}
HalResult<void> HalResult<void>::fromStatus(binder::Status status) {
- if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
+ if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION ||
+ status.transactionError() == android::UNKNOWN_TRANSACTION) {
+ // UNKNOWN_TRANSACTION means the HAL implementation is an older version, so this is
+ // the same as the operation being unsupported by this HAL. Should not retry.
return HalResult<void>::unsupported();
}
if (status.isOk()) {
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 8720d9d..87bc34e 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -42,7 +42,10 @@
static HalResult<T> unsupported() { return HalResult("", /* unsupported= */ true); }
static HalResult<T> fromStatus(binder::Status status, T data) {
- if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
+ if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION ||
+ status.transactionError() == android::UNKNOWN_TRANSACTION) {
+ // UNKNOWN_TRANSACTION means the HAL implementation is an older version, so this is
+ // the same as the operation being unsupported by this HAL. Should not retry.
return HalResult<T>::unsupported();
}
if (status.isOk()) {
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index af0cdb8..7813303 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -189,8 +189,7 @@
.WillRepeatedly(vibrator::TriggerSchedulerCallback());
EXPECT_CALL(*mMockHal.get(), on(Eq(11), _))
.Times(Exactly(1))
- .WillRepeatedly(Return(
- Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ .WillRepeatedly(Return(Status::fromStatusT(UNKNOWN_TRANSACTION)));
EXPECT_CALL(*mMockHal.get(), on(Eq(12), _))
.Times(Exactly(1))
.WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
@@ -228,8 +227,7 @@
EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(0.1f))).Times(Exactly(1));
EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(0.2f)))
.Times(Exactly(1))
- .WillRepeatedly(Return(
- Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ .WillRepeatedly(Return(Status::fromStatusT(UNKNOWN_TRANSACTION)));
EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(0.5f)))
.Times(Exactly(1))
.WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
@@ -265,8 +263,7 @@
EXPECT_CALL(*mMockHal.get(),
alwaysOnEnable(Eq(2), Eq(Effect::TICK), Eq(EffectStrength::MEDIUM)))
.Times(Exactly(1))
- .WillRepeatedly(Return(
- Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ .WillRepeatedly(Return(Status::fromStatusT(UNKNOWN_TRANSACTION)));
EXPECT_CALL(*mMockHal.get(),
alwaysOnEnable(Eq(3), Eq(Effect::POP), Eq(EffectStrength::STRONG)))
.Times(Exactly(1))
@@ -397,8 +394,7 @@
Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_))
.Times(Exactly(1))
- .WillRepeatedly(
- Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ .WillRepeatedly(Return(Status::fromStatusT(UNKNOWN_TRANSACTION)));
EXPECT_CALL(*mMockHal.get(), getFrequencyMinimum(_))
.Times(Exactly(1))
.WillRepeatedly(DoAll(SetArgPointee<0>(F_MIN), Return(Status())));
@@ -411,8 +407,7 @@
Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
EXPECT_CALL(*mMockHal.get(), getBandwidthAmplitudeMap(_))
.Times(Exactly(1))
- .WillRepeatedly(
- Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ .WillRepeatedly(Return(Status::fromStatusT(UNKNOWN_TRANSACTION)));
EXPECT_CALL(*mMockHal.get(), getSupportedBraking(_))
.Times(Exactly(1))
.WillRepeatedly(
@@ -451,8 +446,7 @@
DoAll(SetArgPointee<3>(1000), TriggerCallbackInArg2(), Return(Status())));
EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::POP), Eq(EffectStrength::MEDIUM), _, _))
.Times(Exactly(1))
- .WillRepeatedly(Return(
- Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ .WillRepeatedly(Return(Status::fromStatusT(UNKNOWN_TRANSACTION)));
EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::THUD), Eq(EffectStrength::STRONG), _, _))
.Times(Exactly(1))
.WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
@@ -549,8 +543,7 @@
.WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
EXPECT_CALL(*mMockHal.get(), compose(Eq(singleEffect), _))
.Times(Exactly(1))
- .WillRepeatedly(Return(
- Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ .WillRepeatedly(Return(Status::fromStatusT(UNKNOWN_TRANSACTION)));
EXPECT_CALL(*mMockHal.get(), compose(Eq(multipleEffects), _))
.Times(Exactly(1))
.WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
index 548d028..1593cb1 100644
--- a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
@@ -308,8 +308,7 @@
Return(Status())));
EXPECT_CALL(*mMockHal.get(), triggerSynced(_))
.Times(Exactly(3))
- .WillOnce(Return(
- Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+ .WillOnce(Return(Status::fromStatusT(UNKNOWN_TRANSACTION)))
.WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
.WillRepeatedly(DoAll(TriggerCallback(), Return(Status())));
}
@@ -345,8 +344,7 @@
TEST_F(VibratorManagerHalWrapperAidlTest, TestCancelSynced) {
EXPECT_CALL(*mMockHal.get(), cancelSynced())
.Times(Exactly(3))
- .WillOnce(
- Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+ .WillOnce(Return(Status::fromStatusT(UNKNOWN_TRANSACTION)))
.WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
.WillRepeatedly(Return(Status()));