Merge "Remove unused BufferHubBase::GetBlobFds method"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 49d8fe9..db8848a 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -981,6 +981,8 @@
AddAnrTraceDir(add_to_zip, anr_traces_dir);
+ RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
+
// Slow traces for slow operations.
struct stat st;
int i = 0;
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 00f9f42..49383e5 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -982,9 +982,13 @@
auto to_de = create_data_user_de_path(volume_uuid, user);
int rc = copy_directory_recursive(from_de.c_str(), to_de.c_str());
if (rc != 0) {
- // TODO(narayan): Should we clear clear the rolled back CE data if
- // something goes wrong here ? We're choosing between leaving the
- // app devoid of all its data or with just its ce data installed.
+ if (needs_ce_rollback) {
+ auto ce_data = create_data_user_ce_package_path(volume_uuid, user, package_name);
+ LOG(WARNING) << "de_data rollback failed. Erasing rolled back ce_data " << ce_data;
+ if (delete_dir_contents(ce_data.c_str(), 1, nullptr) != 0) {
+ LOG(WARNING) << "Failed to delete rolled back ce_data " << ce_data;
+ }
+ }
res = error(rc, "Failed copying " + from_de + " to " + to_de);
return res;
}
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 940ba79..a639951 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -314,9 +314,15 @@
bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
vold_decrypt == "1";
- const std::string resolve_startup_string_arg =
+ std::string resolve_startup_string_arg =
+ MapPropertyToArg("persist.device_config.runtime.dex2oat_resolve_startup_strings",
+ "--resolve-startup-const-strings=%s");
+ if (resolve_startup_string_arg.empty()) {
+ // If empty, fall back to system property.
+ resolve_startup_string_arg =
MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
"--resolve-startup-const-strings=%s");
+ }
const std::string image_block_size_arg =
MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size",
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index c0f8e91..1c99663 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -58,6 +58,27 @@
}
}
+static std::vector<apex::ApexFile> ActivateApexPackages() {
+ // The logic here is (partially) copied and adapted from
+ // system/apex/apexd/apexd_main.cpp.
+ //
+ // Only scan the APEX directory under /system (within the chroot dir).
+ // Note that this leaves around the loop devices created and used by
+ // libapexd's code, but this is fine, as we expect to reboot soon after.
+ apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir);
+ return apex::getActivePackages();
+}
+
+static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_packages) {
+ for (const apex::ApexFile& apex_file : active_packages) {
+ const std::string& package_path = apex_file.GetPath();
+ apex::Status status = apex::deactivatePackage(package_path);
+ if (!status.Ok()) {
+ LOG(ERROR) << "Failed to deactivate " << package_path << ": " << status.ErrorMessage();
+ }
+ }
+}
+
// Entry for otapreopt_chroot. Expected parameters are:
// [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params]
// The file descriptor denoted by status-fd will be closed. The rest of the parameters will
@@ -199,15 +220,7 @@
// Try to mount APEX packages in "/apex" in the chroot dir. We need at least
// the Android Runtime APEX, as it is required by otapreopt to run dex2oat.
- // The logic here is (partially) copied and adapted from
- // system/apex/apexd/apexd_main.cpp.
- //
- // Only scan the APEX directory under /system (within the chroot dir).
- // Note that this leaves around the loop devices created and used by
- // libapexd's code, but this is fine, as we expect to reboot soon after.
- apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir);
- // Collect activated packages.
- std::vector<apex::ApexFile> active_packages = apex::getActivePackages();
+ std::vector<apex::ApexFile> active_packages = ActivateApexPackages();
// Now go on and run otapreopt.
@@ -229,14 +242,8 @@
LOG(ERROR) << "Running otapreopt failed: " << error_msg;
}
- // Tear down the work down by the apexd logic above (i.e. deactivate packages).
- for (const apex::ApexFile& apex_file : active_packages) {
- const std::string& package_path = apex_file.GetPath();
- apex::Status status = apex::deactivatePackage(package_path);
- if (!status.Ok()) {
- LOG(ERROR) << "Failed to deactivate " << package_path << ": " << status.ErrorMessage();
- }
- }
+ // Tear down the work down by the apexd logic. (i.e. deactivate packages).
+ DeactivateApexPackages(active_packages);
if (!exec_result) {
exit(213);
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index e2afe1d..78edce0 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -23,6 +23,8 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <binder/Status.h>
@@ -85,6 +87,23 @@
system(cmd.c_str());
}
+template <typename Visitor>
+static void run_cmd_and_process_output(const std::string& cmd, const Visitor& visitor) {
+ FILE* file = popen(cmd.c_str(), "r");
+ CHECK(file != nullptr) << "Failed to ptrace " << cmd;
+ char* line = nullptr;
+ while (true) {
+ size_t n = 0u;
+ ssize_t value = getline(&line, &n, file);
+ if (value == -1) {
+ break;
+ }
+ visitor(line);
+ }
+ free(line);
+ fclose(file);
+}
+
static int mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
int ret = ::mkdir(path.c_str(), mode);
if (ret != 0) {
@@ -222,7 +241,8 @@
::testing::AssertionResult create_mock_app() {
// Create the oat dir.
app_oat_dir_ = app_apk_dir_ + "/oat";
- if (mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755) != 0) {
+ // For debug mode, the directory might already exist. Avoid erroring out.
+ if (mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755) != 0 && !kDebug) {
return ::testing::AssertionFailure() << "Could not create app dir " << app_apk_dir_
<< " : " << strerror(errno);
}
@@ -628,6 +648,50 @@
DEX2OAT_FROM_SCRATCH);
}
+TEST_F(DexoptTest, ResolveStartupConstStrings) {
+ LOG(INFO) << "DexoptDex2oatResolveStartupStrings";
+ const std::string property = "persist.device_config.runtime.dex2oat_resolve_startup_strings";
+ const std::string previous_value = android::base::GetProperty(property, "");
+ auto restore_property = android::base::make_scope_guard([=]() {
+ android::base::SetProperty(property, previous_value);
+ });
+ std::string odex = GetPrimaryDexArtifact(app_oat_dir_.c_str(), apk_path_, "odex");
+ // Disable the property to start.
+ bool found_disable = false;
+ ASSERT_TRUE(android::base::SetProperty(property, "false")) << property;
+ CompilePrimaryDexOk("speed-profile",
+ DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PROFILE_GUIDED |
+ DEXOPT_GENERATE_APP_IMAGE,
+ app_oat_dir_.c_str(),
+ kTestAppGid,
+ DEX2OAT_FROM_SCRATCH);
+ run_cmd_and_process_output(
+ "oatdump --header-only --oat-file=" + odex,
+ [&](const std::string& line) {
+ if (line.find("--resolve-startup-const-strings=false") != std::string::npos) {
+ found_disable = true;
+ }
+ });
+ EXPECT_TRUE(found_disable);
+ // Enable the property and inspect that .art artifact is larger.
+ bool found_enable = false;
+ ASSERT_TRUE(android::base::SetProperty(property, "true")) << property;
+ CompilePrimaryDexOk("speed-profile",
+ DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PROFILE_GUIDED |
+ DEXOPT_GENERATE_APP_IMAGE,
+ app_oat_dir_.c_str(),
+ kTestAppGid,
+ DEX2OAT_FROM_SCRATCH);
+ run_cmd_and_process_output(
+ "oatdump --header-only --oat-file=" + odex,
+ [&](const std::string& line) {
+ if (line.find("--resolve-startup-const-strings=true") != std::string::npos) {
+ found_enable = true;
+ }
+ });
+ EXPECT_TRUE(found_enable);
+}
+
class PrimaryDexReCompilationTest : public DexoptTest {
public:
virtual void SetUp() {
diff --git a/headers/media_plugin/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h
index 4de314d..c87ee56 100644
--- a/headers/media_plugin/media/cas/CasAPI.h
+++ b/headers/media_plugin/media/cas/CasAPI.h
@@ -48,6 +48,14 @@
uint8_t *data,
size_t size);
+typedef void (*CasPluginCallbackExt)(
+ void *appData,
+ int32_t event,
+ int32_t arg,
+ uint8_t *data,
+ size_t size,
+ const CasSessionId *sessionId);
+
struct CasFactory {
CasFactory() {}
virtual ~CasFactory() {}
@@ -67,6 +75,13 @@
CasPluginCallback callback,
CasPlugin **plugin) = 0;
+ // Construct a new extend instance of a CasPlugin given a CA_system_id
+ virtual status_t createPlugin(
+ int32_t CA_system_id,
+ void *appData,
+ CasPluginCallbackExt callback,
+ CasPlugin **plugin) = 0;
+
private:
CasFactory(const CasFactory &);
CasFactory &operator=(const CasFactory &); /* NOLINT */
@@ -110,7 +125,15 @@
int32_t arg,
const CasData &eventData) = 0;
- // Native implementation of the MediaCas Java API provision method.
+ // Deliver an session event to the CasPlugin. The format of the event is
+ // specific to the CA scheme and is opaque to the framework.
+ virtual status_t sendSessionEvent(
+ const CasSessionId &sessionId,
+ int32_t event,
+ int32_t arg,
+ const CasData &eventData) = 0;
+
+ // Native implementation of the MediaCas Java API provision method.
virtual status_t provision(
const String8 &provisionString) = 0;
diff --git a/headers/media_plugin/media/openmax/OMX_AsString.h b/headers/media_plugin/media/openmax/OMX_AsString.h
index 152015b..ce30b41 100644
--- a/headers/media_plugin/media/openmax/OMX_AsString.h
+++ b/headers/media_plugin/media/openmax/OMX_AsString.h
@@ -911,6 +911,9 @@
case OMX_VIDEO_AVCLevel5: return "Level5";
case OMX_VIDEO_AVCLevel51: return "Level51";
case OMX_VIDEO_AVCLevel52: return "Level52";
+ case OMX_VIDEO_AVCLevel6: return "Level6";
+ case OMX_VIDEO_AVCLevel61: return "Level61";
+ case OMX_VIDEO_AVCLevel62: return "Level62";
default: return def;
}
}
diff --git a/headers/media_plugin/media/openmax/OMX_Video.h b/headers/media_plugin/media/openmax/OMX_Video.h
index 9fd2fd2..b6edaa9 100644
--- a/headers/media_plugin/media/openmax/OMX_Video.h
+++ b/headers/media_plugin/media/openmax/OMX_Video.h
@@ -832,6 +832,9 @@
OMX_VIDEO_AVCLevel5 = 0x4000, /**< Level 5 */
OMX_VIDEO_AVCLevel51 = 0x8000, /**< Level 5.1 */
OMX_VIDEO_AVCLevel52 = 0x10000, /**< Level 5.2 */
+ OMX_VIDEO_AVCLevel6 = 0x20000, /**< Level 6 */
+ OMX_VIDEO_AVCLevel61 = 0x40000, /**< Level 6.1 */
+ OMX_VIDEO_AVCLevel62 = 0x80000, /**< Level 6.2 */
OMX_VIDEO_AVCLevelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
OMX_VIDEO_AVCLevelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
OMX_VIDEO_AVCLevelMax = 0x7FFFFFFF
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index f779d6e..49592a8 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -599,17 +599,53 @@
return mHasFds;
}
+void Parcel::updateWorkSourceRequestHeaderPosition() const {
+ // Only update the request headers once. We only want to point
+ // to the first headers read/written.
+ if (!mRequestHeaderPresent) {
+ mWorkSourceRequestHeaderPosition = dataPosition();
+ mRequestHeaderPresent = true;
+ }
+}
+
// Write RPC headers. (previously just the interface token)
status_t Parcel::writeInterfaceToken(const String16& interface)
{
const IPCThreadState* threadState = IPCThreadState::self();
writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
+ updateWorkSourceRequestHeaderPosition();
writeInt32(threadState->shouldPropagateWorkSource() ?
threadState->getCallingWorkSourceUid() : IPCThreadState::kUnsetWorkSource);
// currently the interface identification token is just its name as a string
return writeString16(interface);
}
+bool Parcel::replaceCallingWorkSourceUid(uid_t uid)
+{
+ if (!mRequestHeaderPresent) {
+ return false;
+ }
+
+ const size_t initialPosition = dataPosition();
+ setDataPosition(mWorkSourceRequestHeaderPosition);
+ status_t err = writeInt32(uid);
+ setDataPosition(initialPosition);
+ return err == NO_ERROR;
+}
+
+uid_t Parcel::readCallingWorkSourceUid()
+{
+ if (!mRequestHeaderPresent) {
+ return IPCThreadState::kUnsetWorkSource;
+ }
+
+ const size_t initialPosition = dataPosition();
+ setDataPosition(mWorkSourceRequestHeaderPosition);
+ uid_t uid = readInt32();
+ setDataPosition(initialPosition);
+ return uid;
+}
+
bool Parcel::checkInterface(IBinder* binder) const
{
return enforceInterface(binder->getInterfaceDescriptor());
@@ -634,6 +670,7 @@
threadState->setStrictModePolicy(strictPolicy);
}
// WorkSource.
+ updateWorkSourceRequestHeaderPosition();
int32_t workSource = readInt32();
threadState->setCallingWorkSourceUidWithoutPropagation(workSource);
// Interface descriptor.
@@ -2889,6 +2926,8 @@
mAllowFds = true;
mOwner = nullptr;
mOpenAshmemSize = 0;
+ mWorkSourceRequestHeaderPosition = 0;
+ mRequestHeaderPresent = false;
// racing multiple init leads only to multiple identical write
if (gMaxFds == 0) {
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 240b708..afdfe4f 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -395,6 +395,12 @@
static size_t getGlobalAllocSize();
static size_t getGlobalAllocCount();
+ bool replaceCallingWorkSourceUid(uid_t uid);
+ // Returns the work source provided by the caller. This can only be trusted for trusted calling
+ // uid.
+ uid_t readCallingWorkSourceUid();
+ void readRequestHeaders() const;
+
private:
typedef void (*release_func)(Parcel* parcel,
const uint8_t* data, size_t dataSize,
@@ -429,6 +435,7 @@
void initState();
void scanForFds() const;
status_t validateReadData(size_t len) const;
+ void updateWorkSourceRequestHeaderPosition() const;
template<class T>
status_t readAligned(T *pArg) const;
@@ -477,6 +484,9 @@
mutable size_t mNextObjectHint;
mutable bool mObjectsSorted;
+ mutable bool mRequestHeaderPresent;
+ mutable size_t mWorkSourceRequestHeaderPosition;
+
mutable bool mFdsKnown;
mutable bool mHasFds;
bool mAllowFds;
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 6091d3f..206bc30 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -98,8 +98,8 @@
output.writeInt32(cachedBuffer.bufferId);
output.writeParcelable(metadata);
- output.writeFloat(colorAlpha);
- output.writeUint32(static_cast<uint32_t>(colorDataspace));
+ output.writeFloat(bgColorAlpha);
+ output.writeUint32(static_cast<uint32_t>(bgColorDataspace));
return NO_ERROR;
}
@@ -175,8 +175,8 @@
cachedBuffer.bufferId = input.readInt32();
input.readParcelable(&metadata);
- colorAlpha = input.readFloat();
- colorDataspace = static_cast<ui::Dataspace>(input.readUint32());
+ bgColorAlpha = input.readFloat();
+ bgColorDataspace = static_cast<ui::Dataspace>(input.readUint32());
return NO_ERROR;
}
@@ -390,13 +390,11 @@
what |= eCachedBufferChanged;
cachedBuffer = other.cachedBuffer;
}
- if (other.what & eColorAlphaChanged) {
- what |= eColorAlphaChanged;
- colorAlpha = other.colorAlpha;
- }
- if (other.what & eColorDataspaceChanged) {
- what |= eColorDataspaceChanged;
- colorDataspace = other.colorDataspace;
+ if (other.what & eBackgroundColorChanged) {
+ what |= eBackgroundColorChanged;
+ color = other.color;
+ bgColorAlpha = other.bgColorAlpha;
+ bgColorDataspace = other.bgColorDataspace;
}
if (other.what & eMetadataChanged) {
what |= eMetadataChanged;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index c712bde..51385b8 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -678,31 +678,18 @@
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorAlpha(
- const sp<SurfaceControl>& sc, float alpha) {
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackgroundColor(
+ const sp<SurfaceControl>& sc, const half3& color, float alpha, ui::Dataspace dataspace) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eColorAlphaChanged;
- s->colorAlpha = alpha;
-
- registerSurfaceControlForCallback(sc);
- return *this;
-}
-
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorDataspace(
- const sp<SurfaceControl>& sc, ui::Dataspace dataspace) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
-
- s->what |= layer_state_t::eColorDataspaceChanged;
- s->colorDataspace = dataspace;
+ s->what |= layer_state_t::eBackgroundColorChanged;
+ s->color = color;
+ s->bgColorAlpha = alpha;
+ s->bgColorDataspace = dataspace;
registerSurfaceControlForCallback(sc);
return *this;
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 8e500a4..008f520 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -177,6 +177,12 @@
return mHandle;
}
+sp<IGraphicBufferProducer> SurfaceControl::getIGraphicBufferProducer() const
+{
+ Mutex::Autolock _l(mLock);
+ return mGraphicBufferProducer;
+}
+
sp<SurfaceComposerClient> SurfaceControl::getClient() const
{
return mClient;
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index afd843f..c780c07 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -86,9 +86,8 @@
eCornerRadiusChanged = 0x80000000,
eFrameChanged = 0x1'00000000,
eCachedBufferChanged = 0x2'00000000,
- eColorAlphaChanged = 0x4'00000000,
- eColorDataspaceChanged = 0x8'00000000,
- eMetadataChanged = 0x10'00000000,
+ eBackgroundColorChanged = 0x4'00000000,
+ eMetadataChanged = 0x8'00000000,
};
layer_state_t()
@@ -115,8 +114,8 @@
surfaceDamageRegion(),
api(-1),
colorTransform(mat4()),
- colorAlpha(0),
- colorDataspace(ui::Dataspace::UNKNOWN) {
+ bgColorAlpha(0),
+ bgColorDataspace(ui::Dataspace::UNKNOWN) {
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
hdrMetadata.validTypes = 0;
@@ -187,10 +186,12 @@
cached_buffer_t cachedBuffer;
- float colorAlpha;
- ui::Dataspace colorDataspace;
-
LayerMetadata metadata;
+
+ // The following refer to the alpha, and dataspace, respectively of
+ // the background color layer
+ float bgColorAlpha;
+ ui::Dataspace bgColorDataspace;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 8e2bb2b..a95664b 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -330,11 +330,9 @@
Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color);
- // Sets the alpha of the background color layer if it exists.
- Transaction& setColorAlpha(const sp<SurfaceControl>& sc, float alpha);
-
- // Sets the dataspace of the background color layer if it exists.
- Transaction& setColorDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
+ // Sets the background color of a layer with the specified color, alpha, and dataspace
+ Transaction& setBackgroundColor(const sp<SurfaceControl>& sc, const half3& color,
+ float alpha, ui::Dataspace dataspace);
Transaction& setTransform(const sp<SurfaceControl>& sc, uint32_t transform);
Transaction& setTransformToDisplayInverse(const sp<SurfaceControl>& sc,
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 9bba766..b584f36 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -71,6 +71,8 @@
sp<Surface> createSurface() const;
sp<IBinder> getHandle() const;
+ sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
+
status_t clearLayerFrameStats() const;
status_t getLayerFrameStats(FrameStats* outStats) const;
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 2c4b5f3..92ea07c 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -94,7 +94,7 @@
mMapperV2_1 = IMapper::castFrom(mMapper);
}
-bool Gralloc2Mapper::isSupported() const {
+bool Gralloc2Mapper::isLoaded() const {
return mMapper != nullptr;
}
@@ -359,7 +359,7 @@
}
}
-bool Gralloc2Allocator::isSupported() const {
+bool Gralloc2Allocator::isLoaded() const {
return mAllocator != nullptr;
}
diff --git a/libs/ui/Gralloc3.cpp b/libs/ui/Gralloc3.cpp
index acb6b01..306a74b 100644
--- a/libs/ui/Gralloc3.cpp
+++ b/libs/ui/Gralloc3.cpp
@@ -92,7 +92,7 @@
}
}
-bool Gralloc3Mapper::isSupported() const {
+bool Gralloc3Mapper::isLoaded() const {
return mMapper != nullptr;
}
@@ -322,7 +322,7 @@
}
}
-bool Gralloc3Allocator::isSupported() const {
+bool Gralloc3Allocator::isLoaded() const {
return mAllocator != nullptr;
}
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index da24cf1..15597eb 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -236,15 +236,15 @@
return NO_ERROR;
}
-status_t GraphicBuffer::lock(uint32_t inUsage, void** vaddr)
-{
+status_t GraphicBuffer::lock(uint32_t inUsage, void** vaddr, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) {
const Rect lockBounds(width, height);
- status_t res = lock(inUsage, lockBounds, vaddr);
+ status_t res = lock(inUsage, lockBounds, vaddr, outBytesPerPixel, outBytesPerStride);
return res;
}
-status_t GraphicBuffer::lock(uint32_t inUsage, const Rect& rect, void** vaddr)
-{
+status_t GraphicBuffer::lock(uint32_t inUsage, const Rect& rect, void** vaddr,
+ int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
if (rect.left < 0 || rect.right > width ||
rect.top < 0 || rect.bottom > height) {
ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
@@ -252,10 +252,10 @@
width, height);
return BAD_VALUE;
}
- int32_t bytesPerPixel, bytesPerStride;
- status_t res =
- getBufferMapper().lock(handle, inUsage, rect, vaddr, &bytesPerPixel, &bytesPerStride);
+ status_t res = getBufferMapper().lock(handle, inUsage, rect, vaddr, outBytesPerPixel,
+ outBytesPerStride);
+
return res;
}
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index efb5798..5a67dc4 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -48,12 +48,12 @@
GraphicBufferAllocator::GraphicBufferAllocator() : mMapper(GraphicBufferMapper::getInstance()) {
mAllocator = std::make_unique<const Gralloc3Allocator>(
reinterpret_cast<const Gralloc3Mapper&>(mMapper.getGrallocMapper()));
- if (!mAllocator->isSupported()) {
+ if (!mAllocator->isLoaded()) {
mAllocator = std::make_unique<const Gralloc2Allocator>(
reinterpret_cast<const Gralloc2Mapper&>(mMapper.getGrallocMapper()));
}
- if (!mAllocator->isSupported()) {
+ if (!mAllocator->isLoaded()) {
LOG_ALWAYS_FATAL("gralloc-allocator is missing");
}
}
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 9e36377..79c333f 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -51,11 +51,11 @@
GraphicBufferMapper::GraphicBufferMapper() {
mMapper = std::make_unique<const Gralloc3Mapper>();
- if (!mMapper->isSupported()) {
+ if (!mMapper->isLoaded()) {
mMapper = std::make_unique<const Gralloc2Mapper>();
}
- if (!mMapper->isSupported()) {
+ if (!mMapper->isLoaded()) {
LOG_ALWAYS_FATAL("gralloc-mapper is missing");
}
}
diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h
index a484bce..1b8a930 100644
--- a/libs/ui/include/ui/Gralloc.h
+++ b/libs/ui/include/ui/Gralloc.h
@@ -31,7 +31,7 @@
public:
virtual ~GrallocMapper();
- virtual bool isSupported() const = 0;
+ virtual bool isLoaded() const = 0;
virtual status_t createDescriptor(void* bufferDescriptorInfo,
void* outBufferDescriptor) const = 0;
@@ -74,7 +74,7 @@
public:
virtual ~GrallocAllocator();
- virtual bool isSupported() const = 0;
+ virtual bool isLoaded() const = 0;
virtual std::string dumpDebugInfo() const = 0;
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index b23d8f7..4ef9b51 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -36,7 +36,7 @@
Gralloc2Mapper();
- bool isSupported() const override;
+ bool isLoaded() const override;
status_t createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const override;
@@ -76,7 +76,7 @@
// time.
Gralloc2Allocator(const Gralloc2Mapper& mapper);
- bool isSupported() const override;
+ bool isLoaded() const override;
std::string dumpDebugInfo() const override;
diff --git a/libs/ui/include/ui/Gralloc3.h b/libs/ui/include/ui/Gralloc3.h
index b0cbcc1..879e96e 100644
--- a/libs/ui/include/ui/Gralloc3.h
+++ b/libs/ui/include/ui/Gralloc3.h
@@ -35,7 +35,7 @@
Gralloc3Mapper();
- bool isSupported() const override;
+ bool isLoaded() const override;
status_t createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const override;
@@ -74,7 +74,7 @@
// time.
Gralloc3Allocator(const Gralloc3Mapper& mapper);
- bool isSupported() const override;
+ bool isLoaded() const override;
std::string dumpDebugInfo() const override;
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index b73ca2b..18a27a0 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -169,8 +169,12 @@
bool needsReallocation(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage);
- status_t lock(uint32_t inUsage, void** vaddr);
- status_t lock(uint32_t inUsage, const Rect& rect, void** vaddr);
+ // For the following two lock functions, if bytesPerStride or bytesPerPixel
+ // are unknown or variable, -1 will be returned
+ status_t lock(uint32_t inUsage, void** vaddr, int32_t* outBytesPerPixel = nullptr,
+ int32_t* outBytesPerStride = nullptr);
+ status_t lock(uint32_t inUsage, const Rect& rect, void** vaddr,
+ int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
// For HAL_PIXEL_FORMAT_YCbCr_420_888
status_t lockYCbCr(uint32_t inUsage, android_ycbcr *ycbcr);
status_t lockYCbCr(uint32_t inUsage, const Rect& rect,
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index a47a98f..527a27d 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -10,6 +10,7 @@
#include <mutex>
#include <thread>
+namespace {
#define RETRY_EINTR(fnc_call) \
([&]() -> decltype(fnc_call) { \
decltype(fnc_call) result; \
@@ -30,6 +31,7 @@
using android::dvr::ProducerBuffer;
using android::pdx::LocalHandle;
using android::pdx::Status;
+using LibBufferHubTest = ::testing::Test;
const int kWidth = 640;
const int kHeight = 480;
@@ -41,7 +43,15 @@
android::BufferHubDefs::kMaxNumberOfClients - 1;
const int kPollTimeoutMs = 100;
-using LibBufferHubTest = ::testing::Test;
+// Helper function to poll the eventfd in BufferHubBase.
+template <class BufferHubBase>
+int PollBufferEvent(const std::unique_ptr<BufferHubBase>& buffer,
+ int timeout_ms = kPollTimeoutMs) {
+ pollfd p = {buffer->event_fd(), POLLIN, 0};
+ return poll(&p, 1, timeout_ms);
+}
+
+} // namespace
TEST_F(LibBufferHubTest, TestBasicUsage) {
std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
@@ -61,36 +71,36 @@
EXPECT_EQ(c2->client_state_mask(), kFirstClientBitMask << 2);
// Initial state: producer not available, consumers not available.
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c1)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c2)));
EXPECT_EQ(0, p->GainAsync());
EXPECT_EQ(0, p->Post(LocalHandle()));
// New state: producer not available, consumers available.
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- EXPECT_EQ(1, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
- EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
+ EXPECT_EQ(1, RETRY_EINTR(PollBufferEvent(c1)));
+ EXPECT_EQ(1, RETRY_EINTR(PollBufferEvent(c2)));
LocalHandle fence;
EXPECT_EQ(0, c1->Acquire(&fence));
- EXPECT_EQ(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
- EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c1)));
+ EXPECT_EQ(1, RETRY_EINTR(PollBufferEvent(c2)));
EXPECT_EQ(0, c2->Acquire(&fence));
- EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c2)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c1)));
EXPECT_EQ(0, c1->Release(LocalHandle()));
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(0, c2->Discard());
- EXPECT_EQ(1, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(1, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(0, p->Gain(&fence));
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c1)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c2)));
}
TEST_F(LibBufferHubTest, TestEpoll) {
@@ -225,7 +235,7 @@
// Release in acquired state should succeed.
EXPECT_EQ(0, c->Release(LocalHandle()));
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
// Acquire and post in released state should fail.
EXPECT_EQ(-EBUSY, c->Acquire(&fence));
@@ -266,7 +276,7 @@
EXPECT_FALSE(invalid_fence.IsValid());
// Acquire in posted state should succeed.
- EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c)));
EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
EXPECT_FALSE(invalid_fence.IsValid());
EXPECT_EQ(p->buffer_state(), c->buffer_state());
@@ -281,7 +291,7 @@
// Release in acquired state should succeed.
EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(p->buffer_state(), c->buffer_state());
EXPECT_TRUE(p->is_released());
@@ -387,7 +397,7 @@
for (size_t i = 0; i < kMaxConsumerCount; ++i) {
EXPECT_TRUE(
IsClientPosted(cs[i]->buffer_state(), cs[i]->client_state_mask()));
- EXPECT_LT(0, RETRY_EINTR(cs[i]->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(cs[i])));
EXPECT_EQ(0, cs[i]->AcquireAsync(&metadata, &invalid_fence));
EXPECT_TRUE(
IsClientAcquired(p->buffer_state(), cs[i]->client_state_mask()));
@@ -400,7 +410,7 @@
EXPECT_EQ(0, cs[i]->ReleaseAsync(&metadata, invalid_fence));
}
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_TRUE(p->is_released());
// Buffer state cross all clients must be consistent.
@@ -427,7 +437,7 @@
// Post the gained buffer should signal already created consumer.
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
EXPECT_TRUE(AnyClientPosted(p->buffer_state()));
- EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c)));
EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
EXPECT_TRUE(AnyClientAcquired(c->buffer_state()));
}
@@ -445,7 +455,7 @@
// Post the gained buffer before any consumer gets created.
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
EXPECT_TRUE(p->is_released());
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
// Newly created consumer will be signalled for the posted buffer although it
// is created after producer posting.
@@ -471,7 +481,7 @@
// Post, acquire, and release the buffer..
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
- EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c1)));
EXPECT_EQ(0, c1->AcquireAsync(&metadata, &invalid_fence));
EXPECT_EQ(0, c1->ReleaseAsync(&metadata, invalid_fence));
@@ -479,7 +489,7 @@
// executed before Release impulse gets executed by bufferhubd. Thus, here we
// need to wait until the releasd is confirmed before creating another
// consumer.
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_TRUE(p->is_released());
// Create another consumer immediately after the release, should not make the
@@ -507,14 +517,14 @@
EXPECT_EQ(0, p->GainAsync());
Metadata m = {1, 3};
EXPECT_EQ(0, p->Post(LocalHandle(), &m, sizeof(Metadata)));
- EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LE(0, RETRY_EINTR(PollBufferEvent(c)));
LocalHandle fence;
Metadata m2 = {};
EXPECT_EQ(0, c->Acquire(&fence, &m2, sizeof(m2)));
EXPECT_EQ(m.field1, m2.field1);
EXPECT_EQ(m.field2, m2.field2);
EXPECT_EQ(0, c->Release(LocalHandle()));
- EXPECT_LT(0, RETRY_EINTR(p->Poll(0)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p, /*timeout_ms=*/0)));
}
TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) {
@@ -539,7 +549,7 @@
// buffer allocation.
OverSizedMetadata evil_meta = {};
EXPECT_NE(0, p->Post(LocalHandle(), &evil_meta, sizeof(OverSizedMetadata)));
- EXPECT_GE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_GE(0, RETRY_EINTR(PollBufferEvent(c)));
// It is ok to post metadata smaller than originally requested during
// buffer allocation.
@@ -651,7 +661,7 @@
// Should acquire a valid fence.
LocalHandle f2;
- EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c)));
EXPECT_EQ(0, c->AcquireAsync(&meta, &f2));
EXPECT_TRUE(f2.IsValid());
// The original fence and acquired fence should have different fd number.
@@ -668,7 +678,7 @@
// Should gain an invalid fence.
LocalHandle f3;
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(0, p->GainAsync(&meta, &f3));
EXPECT_FALSE(f3.IsValid());
@@ -677,7 +687,7 @@
// Should acquire a valid fence and it's already signalled.
LocalHandle f4;
- EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c)));
EXPECT_EQ(0, c->AcquireAsync(&meta, &f4));
EXPECT_TRUE(f4.IsValid());
EXPECT_LT(0, PollFd(f4.Get(), kPollTimeoutMs));
@@ -690,7 +700,7 @@
// Should gain a valid fence, which is already signaled.
LocalHandle f6;
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(0, p->GainAsync(&meta, &f6));
EXPECT_TRUE(f6.IsValid());
EXPECT_LT(0, PollFd(f6.Get(), kPollTimeoutMs));
@@ -710,14 +720,14 @@
EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
LocalHandle fence;
- EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c1)));
EXPECT_EQ(0, c1->AcquireAsync(&meta, &fence));
// Destroy the consumer who has acquired but not released the buffer.
c1 = nullptr;
// The buffer is now available for the producer to gain.
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
// Newly added consumer is not able to acquire the buffer.
std::unique_ptr<ConsumerBuffer> c2 =
@@ -725,7 +735,7 @@
ASSERT_TRUE(c2.get() != nullptr);
const uint32_t client_state_mask2 = c2->client_state_mask();
EXPECT_NE(client_state_mask1, client_state_mask2);
- EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c2)));
EXPECT_EQ(-EBUSY, c2->AcquireAsync(&meta, &fence));
// Producer should be able to gain.
@@ -744,7 +754,7 @@
EXPECT_EQ(0, p->GainAsync());
DvrNativeBufferMetadata meta;
EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
- EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c1)));
// c2 is created when the buffer is in posted state. buffer state for c1 is
// posted. Thus, c2 should be automatically set to posted and able to acquire.
@@ -753,7 +763,7 @@
ASSERT_TRUE(c2.get() != nullptr);
const uint32_t client_state_mask2 = c2->client_state_mask();
EXPECT_NE(client_state_mask1, client_state_mask2);
- EXPECT_LT(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c2)));
LocalHandle invalid_fence;
EXPECT_EQ(0, c2->AcquireAsync(&meta, &invalid_fence));
@@ -768,7 +778,7 @@
const uint32_t client_state_mask3 = c3->client_state_mask();
EXPECT_NE(client_state_mask1, client_state_mask3);
EXPECT_NE(client_state_mask2, client_state_mask3);
- EXPECT_LT(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c3)));
EXPECT_EQ(0, c3->AcquireAsync(&meta, &invalid_fence));
// Releasing c2 and c3 in normal ways.
@@ -779,7 +789,7 @@
c1 = nullptr;
// The buffer is now available for the producer to gain.
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
// C4 is created in released state. Thus, it cannot gain the just posted
// buffer.
@@ -788,7 +798,7 @@
ASSERT_TRUE(c4.get() != nullptr);
const uint32_t client_state_mask4 = c4->client_state_mask();
EXPECT_NE(client_state_mask3, client_state_mask4);
- EXPECT_GE(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
+ EXPECT_GE(0, RETRY_EINTR(PollBufferEvent(c3)));
EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &invalid_fence));
// Producer should be able to gain.
@@ -813,7 +823,7 @@
// Detach in posted state should fail.
EXPECT_EQ(0, p->GainAsync());
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
- EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+ EXPECT_GT(RETRY_EINTR(PollBufferEvent(c)), 0);
auto s1 = p->Detach();
EXPECT_FALSE(s1);
@@ -824,7 +834,7 @@
// Detach in released state should fail.
EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
- EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+ EXPECT_GT(RETRY_EINTR(PollBufferEvent(p)), 0);
s1 = p->Detach();
EXPECT_FALSE(s1);
@@ -837,12 +847,12 @@
EXPECT_TRUE(handle.valid());
// Both producer and consumer should have hangup.
- EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+ EXPECT_GT(RETRY_EINTR(PollBufferEvent(p)), 0);
auto s2 = p->GetEventMask(POLLHUP);
EXPECT_TRUE(s2);
EXPECT_EQ(s2.get(), POLLHUP);
- EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+ EXPECT_GT(RETRY_EINTR(PollBufferEvent(c)), 0);
s2 = p->GetEventMask(POLLHUP);
EXPECT_TRUE(s2);
EXPECT_EQ(s2.get(), POLLHUP);
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
index 7d49482..b28d101 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -196,12 +196,6 @@
return 0;
}
-int BufferHubBase::Poll(int timeout_ms) {
- ATRACE_NAME("BufferHubBase::Poll");
- pollfd p = {event_fd(), POLLIN, 0};
- return poll(&p, 1, timeout_ms);
-}
-
int BufferHubBase::Lock(int usage, int x, int y, int width, int height,
void** address) {
return buffer_.Lock(usage, x, y, width, height, address);
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index 1018f27..b6027e6 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -21,9 +21,6 @@
// a file descriptor for the new channel or a negative error code.
Status<LocalChannelHandle> CreateConsumer();
- // Polls the fd for |timeout_ms| milliseconds (-1 for infinity).
- int Poll(int timeout_ms);
-
// Locks the area specified by (x, y, width, height) for a specific usage. If
// the usage is software then |addr| will be updated to point to the address
// of the buffer in virtual memory. The caller should only access/modify the
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index 1f7dd41..cb46494 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -162,15 +162,6 @@
std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/>
mLastDownTimes; //GUARDED_BY(mLock);
void updateLastDownTime(int32_t deviceId, nsecs_t downTime);
- // Should only be accessed through isResetNeeded() and setResetNeeded()
- bool mResetNeeded = false; //GUARDED_BY(mLock);
- /**
- * Check whether reset should be performed. Reset should be performed
- * if the eventTime of the current event is older than mLastDownTime,
- * i.e. a new gesture has already begun, but an older gesture is still being processed.
- */
- bool isResetNeeded(nsecs_t eventTime);
- void setResetNeeded(bool isNeeded);
/**
* Exit the InputClassifier HAL thread.
@@ -188,11 +179,12 @@
class InputClassifier : public InputClassifierInterface {
public:
explicit InputClassifier(const sp<InputListenerInterface>& listener);
- virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
- virtual void notifyKey(const NotifyKeyArgs* args);
- virtual void notifyMotion(const NotifyMotionArgs* args);
- virtual void notifySwitch(const NotifySwitchArgs* args);
- virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
+
+ virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
+ virtual void notifyKey(const NotifyKeyArgs* args) override;
+ virtual void notifyMotion(const NotifyMotionArgs* args) override;
+ virtual void notifySwitch(const NotifySwitchArgs* args) override;
+ virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
private:
std::unique_ptr<MotionClassifierInterface> mMotionClassifier = nullptr;
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index c411ec0..fe1d4d0 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -268,7 +268,7 @@
pointerGestureSwipeMaxWidthRatio(0.25f),
pointerGestureMovementSpeedRatio(0.8f),
pointerGestureZoomSpeedRatio(0.3f),
- showTouches(false) { }
+ showTouches(false), pointerCapture(false) { }
std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const;
std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueDisplayId)
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index e0e211f..0f987c3 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -444,7 +444,7 @@
}
virtual bool updateInfo() {
- mInfo.token = mServerChannel->getToken();
+ mInfo.token = mServerChannel ? mServerChannel->getToken() : nullptr;
mInfo.name = mName;
mInfo.layoutParamsFlags = 0;
mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
@@ -474,8 +474,8 @@
}
void releaseChannel() {
+ mServerChannel.clear();
InputWindowHandle::releaseChannel();
- mDispatcher->unregisterInputChannel(mServerChannel);
}
protected:
virtual bool handled() {
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 2a70293..4c4ee06 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -128,7 +128,6 @@
"DisplayHardware/FramebufferSurface.cpp",
"DisplayHardware/HWC2.cpp",
"DisplayHardware/HWComposer.cpp",
- "DisplayHardware/HWComposerBufferCache.cpp",
"DisplayHardware/PowerAdvisor.cpp",
"DisplayHardware/VirtualDisplaySurface.cpp",
"Effects/Daltonizer.cpp",
@@ -152,6 +151,7 @@
"Scheduler/MessageQueue.cpp",
"Scheduler/Scheduler.cpp",
"Scheduler/SchedulerUtils.cpp",
+ "Scheduler/PhaseOffsets.cpp",
"StartPropertySetThread.cpp",
"SurfaceFlinger.cpp",
"SurfaceInterceptor.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 9662fcd..f986329 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -19,6 +19,28 @@
#define LOG_TAG "BufferLayer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <cmath>
+#include <cstdlib>
+#include <mutex>
+
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/LayerCreationArgs.h>
+#include <cutils/compiler.h>
+#include <cutils/native_handle.h>
+#include <cutils/properties.h>
+#include <gui/BufferItem.h>
+#include <gui/BufferQueue.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/Surface.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/DebugUtils.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/NativeHandle.h>
+#include <utils/StopWatch.h>
+#include <utils/Trace.h>
+
#include "BufferLayer.h"
#include "Colorizer.h"
#include "DisplayDevice.h"
@@ -26,33 +48,13 @@
#include "TimeStats/TimeStats.h"
-#include <renderengine/RenderEngine.h>
-
-#include <gui/BufferItem.h>
-#include <gui/BufferQueue.h>
-#include <gui/LayerDebugInfo.h>
-#include <gui/Surface.h>
-
-#include <ui/DebugUtils.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/NativeHandle.h>
-#include <utils/StopWatch.h>
-#include <utils/Trace.h>
-
-#include <cutils/compiler.h>
-#include <cutils/native_handle.h>
-#include <cutils/properties.h>
-
-#include <math.h>
-#include <stdlib.h>
-#include <mutex>
-
namespace android {
BufferLayer::BufferLayer(const LayerCreationArgs& args)
- : Layer(args), mTextureName(args.flinger->getNewTexture()) {
+ : Layer(args),
+ mTextureName(args.flinger->getNewTexture()),
+ mCompositionLayer{mFlinger->getCompositionEngine().createLayer(
+ compositionengine::LayerCreationArgs{this})} {
ALOGV("Creating Layer %s", args.name.string());
mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
@@ -649,6 +651,10 @@
return Rect(bufWidth, bufHeight);
}
+std::shared_ptr<compositionengine::Layer> BufferLayer::getCompositionLayer() const {
+ return mCompositionLayer;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 3fe8ed0..d0c1b13 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -16,35 +16,32 @@
#pragma once
-#include "BufferLayerConsumer.h"
-#include "Client.h"
-#include "Layer.h"
-#include "DisplayHardware/HWComposer.h"
-#include "DisplayHardware/HWComposerBufferCache.h"
-#include "FrameTracker.h"
-#include "LayerVector.h"
-#include "MonitoredProducer.h"
-#include "SurfaceFlinger.h"
+#include <sys/types.h>
+#include <cstdint>
+#include <list>
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
#include <renderengine/Image.h>
#include <renderengine/Mesh.h>
#include <renderengine/Texture.h>
+#include <system/window.h> // For NATIVE_WINDOW_SCALING_MODE_FREEZE
#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
#include <ui/Region.h>
-
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/Timers.h>
-#include <system/window.h> // For NATIVE_WINDOW_SCALING_MODE_FREEZE
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <list>
+#include "BufferLayerConsumer.h"
+#include "Client.h"
+#include "DisplayHardware/HWComposer.h"
+#include "FrameTracker.h"
+#include "Layer.h"
+#include "LayerVector.h"
+#include "MonitoredProducer.h"
+#include "SurfaceFlinger.h"
namespace android {
@@ -57,6 +54,8 @@
// Overriden from Layer
// -----------------------------------------------------------------------
public:
+ std::shared_ptr<compositionengine::Layer> getCompositionLayer() const override;
+
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
// one empty rect.
@@ -187,6 +186,8 @@
bool mBufferLatched{false}; // TODO: Use mActiveBuffer?
Rect getBufferSize(const State& s) const override;
+
+ std::shared_ptr<compositionengine::Layer> mCompositionLayer;
};
} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 96a66cb..2005d20 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -303,48 +303,6 @@
return true;
}
-bool BufferStateLayer::setColor(const half3& color) {
- // create color layer if one does not yet exist
- if (!mCurrentState.bgColorLayer) {
- uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor;
- const String8& name = mName + "BackgroundColorLayer";
- mCurrentState.bgColorLayer =
- new ColorLayer(LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, flags));
-
- // add to child list
- addChild(mCurrentState.bgColorLayer);
- mFlinger->mLayersAdded = true;
- // set up SF to handle added color layer
- if (isRemovedFromCurrentState()) {
- mCurrentState.bgColorLayer->onRemovedFromCurrentState();
- }
- mFlinger->setTransactionFlags(eTransactionNeeded);
- }
-
- mCurrentState.bgColorLayer->setColor(color);
- mCurrentState.bgColorLayer->setLayer(std::numeric_limits<int32_t>::min());
-
- return true;
-}
-
-bool BufferStateLayer::setColorAlpha(float alpha) {
- if (!mCurrentState.bgColorLayer) {
- ALOGE("Attempting to set color alpha on a buffer state layer with no background color");
- return false;
- }
- mCurrentState.bgColorLayer->setAlpha(alpha);
- return true;
-}
-
-bool BufferStateLayer::setColorDataspace(ui::Dataspace dataspace) {
- if (!mCurrentState.bgColorLayer) {
- ALOGE("Attempting to set color dataspace on a buffer state layer with no background color");
- return false;
- }
- mCurrentState.bgColorLayer->setDataspace(dataspace);
- return true;
-}
-
Rect BufferStateLayer::getBufferSize(const State& s) const {
// for buffer state layers we use the display frame size as the buffer size.
if (getActiveWidth(s) < UINT32_MAX && getActiveHeight(s) < UINT32_MAX) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index bef9f19..138bb4c 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -82,9 +82,6 @@
}
bool setCrop_legacy(const Rect& /*crop*/, bool /*immediate*/) override { return false; }
bool setOverrideScalingMode(int32_t /*overrideScalingMode*/) override { return false; }
- bool setColor(const half3& color) override;
- bool setColorAlpha(float alpha) override;
- bool setColorDataspace(ui::Dataspace dataspace) override;
void deferTransactionUntil_legacy(const sp<IBinder>& /*barrierHandle*/,
uint64_t /*frameNumber*/) override {}
void deferTransactionUntil_legacy(const sp<Layer>& /*barrierLayer*/,
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 34082c3..d82ff0e 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -22,6 +22,9 @@
#include <stdlib.h>
#include <sys/types.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/LayerCreationArgs.h>
#include <renderengine/RenderEngine.h>
#include <ui/GraphicBuffer.h>
#include <utils/Errors.h>
@@ -34,7 +37,10 @@
namespace android {
// ---------------------------------------------------------------------------
-ColorLayer::ColorLayer(const LayerCreationArgs& args) : Layer(args) {}
+ColorLayer::ColorLayer(const LayerCreationArgs& args)
+ : Layer(args),
+ mCompositionLayer{mFlinger->getCompositionEngine().createLayer(
+ compositionengine::LayerCreationArgs{this})} {}
ColorLayer::~ColorLayer() = default;
@@ -52,6 +58,21 @@
return !isHiddenByPolicy() && getAlpha() > 0.0f;
}
+bool ColorLayer::setColor(const half3& color) {
+ if (mCurrentState.color.r == color.r && mCurrentState.color.g == color.g &&
+ mCurrentState.color.b == color.b) {
+ return false;
+ }
+
+ mCurrentState.sequence++;
+ mCurrentState.color.r = color.r;
+ mCurrentState.color.g = color.g;
+ mCurrentState.color.b = color.b;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
void ColorLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
const Rect& viewport, int32_t /* supportedPerFrameMetadata */) {
RETURN_IF_NO_HWC_LAYER(displayId);
@@ -113,6 +134,10 @@
getBE().compositionInfo.hwc.surfaceDamage = surfaceDamageRegion;
}
+std::shared_ptr<compositionengine::Layer> ColorLayer::getCompositionLayer() const {
+ return mCompositionLayer;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index f43fc3c..ed4c2d8 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -28,9 +28,13 @@
explicit ColorLayer(const LayerCreationArgs&);
~ColorLayer() override;
+ std::shared_ptr<compositionengine::Layer> getCompositionLayer() const override;
+
virtual const char* getTypeId() const { return "ColorLayer"; }
bool isVisible() const override;
+ bool setColor(const half3& color) override;
+
void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
int32_t supportedPerFrameMetadata) override;
@@ -41,6 +45,9 @@
virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
bool useIdentityTransform, Region& clearRegion,
renderengine::LayerSettings& layer);
+
+private:
+ std::shared_ptr<compositionengine::Layer> mCompositionLayer;
};
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 49fa84a..ce6b06c 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -41,8 +41,11 @@
"src/DisplayColorProfile.cpp",
"src/DisplaySurface.cpp",
"src/DumpHelpers.cpp",
+ "src/HwcBufferCache.cpp",
+ "src/Layer.cpp",
"src/Output.cpp",
"src/OutputCompositionState.cpp",
+ "src/OutputLayer.cpp",
"src/RenderSurface.cpp",
],
local_include_dirs: ["include"],
@@ -57,7 +60,10 @@
"mock/Display.cpp",
"mock/DisplayColorProfile.cpp",
"mock/DisplaySurface.cpp",
+ "mock/Layer.cpp",
+ "mock/LayerFE.cpp",
"mock/Output.cpp",
+ "mock/OutputLayer.cpp",
"mock/RenderSurface.cpp",
],
static_libs: [
@@ -77,8 +83,11 @@
"tests/CompositionEngineTest.cpp",
"tests/DisplayColorProfileTest.cpp",
"tests/DisplayTest.cpp",
+ "tests/HwcBufferCacheTest.cpp",
+ "tests/LayerTest.cpp",
"tests/MockHWComposer.cpp",
"tests/OutputTest.cpp",
+ "tests/OutputLayerTest.cpp",
"tests/RenderSurfaceTest.cpp",
],
static_libs: [
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
index 30cdb49..896f8aa 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
@@ -29,8 +29,10 @@
namespace compositionengine {
class Display;
+class Layer;
struct DisplayCreationArgs;
+struct LayerCreationArgs;
/**
* Encapsulates all the interfaces and implementation details for performing
@@ -42,6 +44,7 @@
// Create a composition Display
virtual std::shared_ptr<Display> createDisplay(DisplayCreationArgs&&) = 0;
+ virtual std::shared_ptr<Layer> createLayer(LayerCreationArgs&&) = 0;
virtual HWComposer& getHwComposer() const = 0;
virtual void setHwComposer(std::unique_ptr<HWComposer>) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
new file mode 100644
index 0000000..29a7dea
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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 <cstdint>
+
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+typedef int64_t nsecs_t;
+
+namespace compositionengine {
+
+class Display;
+class LayerFE;
+
+/**
+ * A layer contains the output-independent composition state for a front-end
+ * Layer
+ */
+class Layer {
+public:
+ virtual ~Layer();
+
+ // Gets the front-end interface for this layer. Can return nullptr if the
+ // front-end layer no longer exists.
+ virtual sp<LayerFE> getLayerFE() const = 0;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerCreationArgs.h
new file mode 100644
index 0000000..db3312b
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerCreationArgs.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019 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 <utils/RefBase.h>
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+class LayerFE;
+
+/**
+ * A parameter object for creating Layer instances
+ */
+struct LayerCreationArgs {
+ // A weak pointer to the front-end layer instance that the new layer will
+ // represent.
+ wp<LayerFE> layerFE;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
new file mode 100644
index 0000000..f9a3624
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019 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 <utils/RefBase.h>
+
+namespace android::compositionengine {
+
+// Defines the interface used by the CompositionEngine to make requests
+// of the front-end layer
+class LayerFE : public virtual RefBase {};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 6be4ad8..84b2423 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -23,11 +23,15 @@
#include <ui/GraphicTypes.h>
#include <ui/Region.h>
#include <ui/Transform.h>
+#include <utils/StrongPointer.h>
namespace android::compositionengine {
class DisplayColorProfile;
+class Layer;
+class LayerFE;
class RenderSurface;
+class OutputLayer;
namespace impl {
struct OutputCompositionState;
@@ -38,6 +42,10 @@
*/
class Output {
public:
+ using OutputLayers = std::vector<std::unique_ptr<compositionengine::OutputLayer>>;
+
+ virtual ~Output();
+
// Returns true if the output is valid. This is meant to be checked post-
// construction and prior to use, as not everything is set up by the
// constructor.
@@ -102,9 +110,23 @@
// this output allows that.
virtual bool belongsInOutput(uint32_t layerStackId, bool internalOnly) const = 0;
-protected:
- ~Output() = default;
+ // Returns a pointer to the output layer corresponding to the given layer on
+ // this output, or nullptr if the layer does not have one
+ virtual OutputLayer* getOutputLayerForLayer(Layer*) const = 0;
+ // Gets the OutputLayer corresponding to the input Layer instance from the
+ // current ordered set of output layers. If there is no such layer, a new
+ // one is created and returned.
+ virtual std::unique_ptr<OutputLayer> getOrCreateOutputLayer(std::shared_ptr<Layer>,
+ sp<LayerFE>) = 0;
+
+ // Sets the new ordered set of output layers for this output
+ virtual void setOutputLayersOrderedByZ(OutputLayers&&) = 0;
+
+ // Gets the ordered set of output layers for this output
+ virtual const OutputLayers& getOutputLayersOrderedByZ() const = 0;
+
+protected:
virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
new file mode 100644
index 0000000..4b8ef38
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 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 <utils/StrongPointer.h>
+
+namespace android::compositionengine {
+
+class Output;
+class Layer;
+class LayerFE;
+
+/**
+ * An output layer contains the output-dependent composition state for a layer
+ */
+class OutputLayer {
+public:
+ virtual ~OutputLayer();
+
+ // Gets the output which owns this output layer
+ virtual const Output& getOutput() const = 0;
+
+ // Gets the display-independent layer which this output layer represents
+ virtual Layer& getLayer() const = 0;
+
+ // Gets the front-end layer interface this output layer represents
+ virtual LayerFE& getLayerFE() const = 0;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
index e23c431..b01eb64 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -27,6 +27,8 @@
std::shared_ptr<compositionengine::Display> createDisplay(
compositionengine::DisplayCreationArgs&&) override;
+ std::shared_ptr<compositionengine::Layer> createLayer(
+ compositionengine::LayerCreationArgs&&) override;
HWComposer& getHwComposer() const override;
void setHwComposer(std::unique_ptr<HWComposer>) override;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
similarity index 79%
rename from services/surfaceflinger/DisplayHardware/HWComposerBufferCache.h
rename to services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index a008ca9..b45de5a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -14,20 +14,19 @@
* limitations under the License.
*/
-#ifndef ANDROID_SF_HWCOMPOSERBUFFERCACHE_H
-#define ANDROID_SF_HWCOMPOSERBUFFERCACHE_H
+#pragma once
-#include <stdint.h>
+#include <cstdint>
+#include <vector>
#include <utils/StrongPointer.h>
-#include <vector>
-
namespace android {
-// ---------------------------------------------------------------------------
class GraphicBuffer;
+namespace compositionengine::impl {
+
// With HIDLized hwcomposer HAL, the HAL can maintain a buffer cache for each
// HWC display and layer. When updating a display target or a layer buffer,
// we have the option to send the buffer handle over or to request the HAL to
@@ -37,17 +36,17 @@
//
// To be able to find out whether a buffer is already in the HAL's cache, we
// use HWComposerBufferCache to mirror the cache in SF.
-class HWComposerBufferCache {
+class HwcBufferCache {
public:
- HWComposerBufferCache();
+ HwcBufferCache();
// Given a buffer queue slot and buffer, return the HWC cache slot and
// buffer to be sent to HWC.
//
// outBuffer is set to buffer when buffer is not in the HWC cache;
// otherwise, outBuffer is set to nullptr.
- void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer,
- uint32_t* outSlot, sp<GraphicBuffer>* outBuffer);
+ void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+ sp<GraphicBuffer>* outBuffer);
private:
// a vector as we expect "slot" to be in the range of [0, 63] (that is,
@@ -55,7 +54,5 @@
std::vector<sp<GraphicBuffer>> mBuffers;
};
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SF_HWCOMPOSERBUFFERCACHE_H
+} // namespace compositionengine::impl
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
new file mode 100644
index 0000000..631351b
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 <memory>
+
+#include <compositionengine/Layer.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+class LayerFE;
+
+struct LayerCreationArgs;
+
+namespace impl {
+
+class Display;
+
+class Layer : public compositionengine::Layer {
+public:
+ Layer(const CompositionEngine&, compositionengine::LayerCreationArgs&&);
+ ~Layer() override;
+
+ sp<LayerFE> getLayerFE() const override;
+
+private:
+ const compositionengine::CompositionEngine& mCompositionEngine;
+ const wp<LayerFE> mLayerFE;
+};
+
+std::shared_ptr<compositionengine::Layer> createLayer(const compositionengine::CompositionEngine&,
+ compositionengine::LayerCreationArgs&&);
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 4be0706..3fd057c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -17,6 +17,8 @@
#pragma once
#include <memory>
+#include <utility>
+#include <vector>
#include <compositionengine/Output.h>
#include <compositionengine/impl/OutputCompositionState.h>
@@ -24,13 +26,15 @@
namespace android::compositionengine {
class CompositionEngine;
+class Layer;
+class OutputLayer;
namespace impl {
class Output : public virtual compositionengine::Output {
public:
Output(const CompositionEngine&);
- virtual ~Output();
+ ~Output() override;
bool isValid() const override;
@@ -60,6 +64,13 @@
Region getDirtyRegion(bool repaintEverything) const override;
bool belongsInOutput(uint32_t, bool) const override;
+ compositionengine::OutputLayer* getOutputLayerForLayer(
+ compositionengine::Layer*) const override;
+ std::unique_ptr<compositionengine::OutputLayer> getOrCreateOutputLayer(
+ std::shared_ptr<compositionengine::Layer>, sp<LayerFE>) override;
+ void setOutputLayersOrderedByZ(OutputLayers&&) override;
+ const OutputLayers& getOutputLayersOrderedByZ() const override;
+
// Testing
void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
@@ -79,6 +90,8 @@
std::unique_ptr<compositionengine::DisplayColorProfile> mDisplayColorProfile;
std::unique_ptr<compositionengine::RenderSurface> mRenderSurface;
+
+ OutputLayers mOutputLayersOrderedByZ;
};
} // namespace impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
new file mode 100644
index 0000000..f3d0258
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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 <memory>
+
+#include <compositionengine/OutputLayer.h>
+
+namespace android::compositionengine::impl {
+
+class OutputLayer : public compositionengine::OutputLayer {
+public:
+ OutputLayer(const compositionengine::Output&, std::shared_ptr<compositionengine::Layer>,
+ sp<compositionengine::LayerFE>);
+ ~OutputLayer() override;
+
+ const compositionengine::Output& getOutput() const override;
+ compositionengine::Layer& getLayer() const override;
+ compositionengine::LayerFE& getLayerFE() const override;
+
+private:
+ const compositionengine::Output& mOutput;
+ std::shared_ptr<compositionengine::Layer> mLayer;
+ sp<compositionengine::LayerFE> mLayerFE;
+};
+
+std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
+ const compositionengine::Output&, std::shared_ptr<compositionengine::Layer>,
+ sp<compositionengine::LayerFE>);
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
index 1967666..0f57685 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
@@ -18,6 +18,7 @@
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/LayerCreationArgs.h>
#include <gmock/gmock.h>
#include <renderengine/RenderEngine.h>
@@ -31,6 +32,7 @@
~CompositionEngine() override;
MOCK_METHOD1(createDisplay, std::shared_ptr<Display>(DisplayCreationArgs&&));
+ MOCK_METHOD1(createLayer, std::shared_ptr<Layer>(LayerCreationArgs&&));
MOCK_CONST_METHOD0(getHwComposer, HWComposer&());
MOCK_METHOD1(setHwComposer, void(std::unique_ptr<HWComposer>));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
new file mode 100644
index 0000000..a7cc08e
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 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/Layer.h>
+#include <compositionengine/LayerFE.h>
+#include <gmock/gmock.h>
+
+namespace android::compositionengine::mock {
+
+class Layer : public compositionengine::Layer {
+public:
+ Layer();
+ virtual ~Layer();
+
+ MOCK_CONST_METHOD0(getLayerFE, sp<LayerFE>());
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
new file mode 100644
index 0000000..92e0070
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 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/LayerFE.h>
+#include <gmock/gmock.h>
+
+namespace android::compositionengine::mock {
+
+// Defines the interface used by the CompositionEngine to make requests
+// of the front-end layer.
+class LayerFE : public compositionengine::LayerFE {
+public:
+ LayerFE();
+ virtual ~LayerFE();
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index e767ad3..2972ad7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -17,7 +17,10 @@
#pragma once
#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/LayerFE.h>
#include <compositionengine/Output.h>
+#include <compositionengine/OutputLayer.h>
#include <compositionengine/RenderSurface.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <gmock/gmock.h>
@@ -55,6 +58,15 @@
MOCK_CONST_METHOD1(getDirtyRegion, Region(bool));
MOCK_CONST_METHOD2(belongsInOutput, bool(uint32_t, bool));
+
+ MOCK_CONST_METHOD1(getOutputLayerForLayer,
+ compositionengine::OutputLayer*(compositionengine::Layer*));
+ MOCK_METHOD2(getOrCreateOutputLayer,
+ std::unique_ptr<compositionengine::OutputLayer>(
+ std::shared_ptr<compositionengine::Layer>,
+ sp<compositionengine::LayerFE>));
+ MOCK_METHOD1(setOutputLayersOrderedByZ, void(OutputLayers&&));
+ MOCK_CONST_METHOD0(getOutputLayersOrderedByZ, OutputLayers&());
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
new file mode 100644
index 0000000..f5e5026
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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/Layer.h>
+#include <compositionengine/LayerFE.h>
+#include <compositionengine/Output.h>
+#include <compositionengine/OutputLayer.h>
+#include <gmock/gmock.h>
+
+namespace android::compositionengine::mock {
+
+class OutputLayer : public compositionengine::OutputLayer {
+public:
+ OutputLayer();
+ virtual ~OutputLayer();
+
+ MOCK_CONST_METHOD0(getOutput, const compositionengine::Output&());
+ MOCK_CONST_METHOD0(getLayer, compositionengine::Layer&());
+ MOCK_CONST_METHOD0(getLayerFE, compositionengine::LayerFE&());
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/mock/Layer.cpp b/services/surfaceflinger/CompositionEngine/mock/Layer.cpp
new file mode 100644
index 0000000..08483cb
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/mock/Layer.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019 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 <compositionengine/mock/Layer.h>
+
+namespace android::compositionengine::mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+Layer::Layer() = default;
+Layer::~Layer() = default;
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/mock/LayerFE.cpp b/services/surfaceflinger/CompositionEngine/mock/LayerFE.cpp
new file mode 100644
index 0000000..607eaad
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/mock/LayerFE.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019 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 <compositionengine/mock/LayerFE.h>
+
+namespace android::compositionengine::mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+LayerFE::LayerFE() = default;
+LayerFE::~LayerFE() = default;
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/mock/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/mock/OutputLayer.cpp
new file mode 100644
index 0000000..4da9377
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/mock/OutputLayer.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019 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 <compositionengine/mock/OutputLayer.h>
+
+namespace android::compositionengine::mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+OutputLayer::OutputLayer() = default;
+OutputLayer::~OutputLayer() = default;
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 127d729..cb08b81 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -16,6 +16,7 @@
#include <compositionengine/impl/CompositionEngine.h>
#include <compositionengine/impl/Display.h>
+#include <compositionengine/impl/Layer.h>
#include <renderengine/RenderEngine.h>
#include "DisplayHardware/HWComposer.h"
@@ -38,6 +39,10 @@
return compositionengine::impl::createDisplay(*this, std::move(args));
}
+std::shared_ptr<compositionengine::Layer> CompositionEngine::createLayer(LayerCreationArgs&& args) {
+ return compositionengine::impl::createLayer(*this, std::move(args));
+}
+
HWComposer& CompositionEngine::getHwComposer() const {
return *mHwComposer.get();
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
similarity index 75%
rename from services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp
rename to services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index a234b63..6f340b9 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -14,21 +14,18 @@
* limitations under the License.
*/
-#include "HWComposerBufferCache.h"
-
+#include <compositionengine/impl/HwcBufferCache.h>
#include <gui/BufferQueue.h>
+#include <ui/GraphicBuffer.h>
-namespace android {
+namespace android::compositionengine::impl {
-HWComposerBufferCache::HWComposerBufferCache()
-{
+HwcBufferCache::HwcBufferCache() {
mBuffers.reserve(BufferQueue::NUM_BUFFER_SLOTS);
}
-void HWComposerBufferCache::getHwcBuffer(int slot,
- const sp<GraphicBuffer>& buffer,
- uint32_t* outSlot, sp<GraphicBuffer>* outBuffer)
-{
+void HwcBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+ sp<GraphicBuffer>* outBuffer) {
if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0) {
// default to slot 0
slot = 0;
@@ -51,4 +48,4 @@
}
}
-} // namespace android
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Layer.cpp b/services/surfaceflinger/CompositionEngine/src/Layer.cpp
new file mode 100644
index 0000000..aaa758e
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/Layer.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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 <compositionengine/CompositionEngine.h>
+#include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/LayerFE.h>
+#include <compositionengine/impl/Layer.h>
+
+namespace android::compositionengine {
+
+Layer::~Layer() = default;
+
+namespace impl {
+
+std::shared_ptr<compositionengine::Layer> createLayer(
+ const compositionengine::CompositionEngine& compositionEngine,
+ compositionengine::LayerCreationArgs&& args) {
+ return std::make_shared<Layer>(compositionEngine, std::move(args));
+}
+
+Layer::Layer(const CompositionEngine& compositionEngine, LayerCreationArgs&& args)
+ : mCompositionEngine(compositionEngine), mLayerFE(args.layerFE) {
+ static_cast<void>(mCompositionEngine); // Temporary use to prevent an unused warning
+}
+
+Layer::~Layer() = default;
+
+sp<LayerFE> Layer::getLayerFE() const {
+ return mLayerFE.promote();
+}
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index c4d563f..f6c1a33 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -17,11 +17,17 @@
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/LayerFE.h>
#include <compositionengine/RenderSurface.h>
#include <compositionengine/impl/Output.h>
+#include <compositionengine/impl/OutputLayer.h>
#include <ui/DebugUtils.h>
-namespace android::compositionengine::impl {
+namespace android::compositionengine {
+
+Output::~Output() = default;
+
+namespace impl {
Output::Output(const CompositionEngine& compositionEngine)
: mCompositionEngine(compositionEngine) {}
@@ -178,8 +184,37 @@
return (layerStackId == mState.layerStackId) && (!internalOnly || mState.layerStackInternal);
}
+compositionengine::OutputLayer* Output::getOutputLayerForLayer(
+ compositionengine::Layer* layer) const {
+ for (const auto& outputLayer : mOutputLayersOrderedByZ) {
+ if (outputLayer && &outputLayer->getLayer() == layer) {
+ return outputLayer.get();
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<compositionengine::OutputLayer> Output::getOrCreateOutputLayer(
+ std::shared_ptr<compositionengine::Layer> layer, sp<compositionengine::LayerFE> layerFE) {
+ for (auto& outputLayer : mOutputLayersOrderedByZ) {
+ if (outputLayer && &outputLayer->getLayer() == layer.get()) {
+ return std::move(outputLayer);
+ }
+ }
+ return createOutputLayer(*this, layer, layerFE);
+}
+
+void Output::setOutputLayersOrderedByZ(OutputLayers&& layers) {
+ mOutputLayersOrderedByZ = std::move(layers);
+}
+
+const Output::OutputLayers& Output::getOutputLayersOrderedByZ() const {
+ return mOutputLayersOrderedByZ;
+}
+
void Output::dirtyEntireOutput() {
mState.dirtyRegion.set(mState.bounds);
}
-} // namespace android::compositionengine::impl
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
new file mode 100644
index 0000000..e95f3a6
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 <compositionengine/Layer.h>
+#include <compositionengine/LayerFE.h>
+#include <compositionengine/Output.h>
+#include <compositionengine/impl/OutputLayer.h>
+
+namespace android::compositionengine {
+
+OutputLayer::~OutputLayer() = default;
+
+namespace impl {
+
+std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
+ const compositionengine::Output& display, std::shared_ptr<compositionengine::Layer> layer,
+ sp<compositionengine::LayerFE> layerFE) {
+ return std::make_unique<OutputLayer>(display, layer, layerFE);
+}
+
+OutputLayer::OutputLayer(const Output& output, std::shared_ptr<Layer> layer, sp<LayerFE> layerFE)
+ : mOutput(output), mLayer(layer), mLayerFE(layerFE) {}
+
+OutputLayer::~OutputLayer() = default;
+
+const compositionengine::Output& OutputLayer::getOutput() const {
+ return mOutput;
+}
+
+compositionengine::Layer& OutputLayer::getLayer() const {
+ return *mLayer;
+}
+
+compositionengine::LayerFE& OutputLayer::getLayerFE() const {
+ return *mLayerFE;
+}
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
new file mode 100644
index 0000000..f2a1aad
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2019 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 <compositionengine/impl/HwcBufferCache.h>
+#include <gtest/gtest.h>
+#include <gui/BufferQueue.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android::compositionengine {
+namespace {
+
+class HwcBufferCacheTest : public testing::Test {
+public:
+ ~HwcBufferCacheTest() override = default;
+
+ void testSlot(const int inSlot, const uint32_t expectedSlot) {
+ uint32_t outSlot;
+ sp<GraphicBuffer> outBuffer;
+
+ // The first time, the output is the same as the input
+ mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
+ EXPECT_EQ(expectedSlot, outSlot);
+ EXPECT_EQ(mBuffer1, outBuffer);
+
+ // The second time with the same buffer, the outBuffer is nullptr.
+ mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
+ EXPECT_EQ(expectedSlot, outSlot);
+ EXPECT_EQ(nullptr, outBuffer.get());
+
+ // With a new buffer, the outBuffer is the input.
+ mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
+ EXPECT_EQ(expectedSlot, outSlot);
+ EXPECT_EQ(mBuffer2, outBuffer);
+
+ // Again, the second request with the same buffer sets outBuffer to nullptr.
+ mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
+ EXPECT_EQ(expectedSlot, outSlot);
+ EXPECT_EQ(nullptr, outBuffer.get());
+
+ // Setting a slot to use nullptr lookslike works, but note that
+ // the output values make it look like no new buffer is being set....
+ mCache.getHwcBuffer(inSlot, sp<GraphicBuffer>(), &outSlot, &outBuffer);
+ EXPECT_EQ(expectedSlot, outSlot);
+ EXPECT_EQ(nullptr, outBuffer.get());
+ }
+
+ impl::HwcBufferCache mCache;
+ sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+};
+
+TEST_F(HwcBufferCacheTest, cacheWorksForSlotZero) {
+ testSlot(0, 0);
+}
+
+TEST_F(HwcBufferCacheTest, cacheWorksForMaxSlot) {
+ testSlot(BufferQueue::NUM_BUFFER_SLOTS - 1, BufferQueue::NUM_BUFFER_SLOTS - 1);
+}
+
+TEST_F(HwcBufferCacheTest, cacheMapsNegativeSlotToZero) {
+ testSlot(-123, 0);
+}
+
+TEST_F(HwcBufferCacheTest, cacheMapsInvalidBufferSlotToZero) {
+ testSlot(BufferQueue::INVALID_BUFFER_SLOT, 0);
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp
new file mode 100644
index 0000000..26115a3
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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 <gtest/gtest.h>
+
+#include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/impl/Layer.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/LayerFE.h>
+
+namespace android::compositionengine {
+namespace {
+
+using testing::StrictMock;
+
+class LayerTest : public testing::Test {
+public:
+ ~LayerTest() override = default;
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ sp<LayerFE> mLayerFE = new StrictMock<mock::LayerFE>();
+ impl::Layer mLayer{mCompositionEngine, LayerCreationArgs{mLayerFE}};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(LayerTest, canInstantiateLayer) {}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
new file mode 100644
index 0000000..0a929ac
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 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 <compositionengine/impl/OutputLayer.h>
+#include <compositionengine/mock/Layer.h>
+#include <compositionengine/mock/LayerFE.h>
+#include <compositionengine/mock/Output.h>
+#include <gtest/gtest.h>
+
+namespace android::compositionengine {
+namespace {
+
+using testing::StrictMock;
+
+class OutputLayerTest : public testing::Test {
+public:
+ ~OutputLayerTest() override = default;
+
+ compositionengine::mock::Output mOutput;
+ std::shared_ptr<compositionengine::mock::Layer> mLayer{
+ new StrictMock<compositionengine::mock::Layer>()};
+ sp<compositionengine::mock::LayerFE> mLayerFE{
+ new StrictMock<compositionengine::mock::LayerFE>()};
+ impl::OutputLayer mOutputLayer{mOutput, mLayer, mLayerFE};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(OutputLayerTest, canInstantiateOutputLayer) {}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 0df1dab..314d98b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -19,6 +19,9 @@
#include <compositionengine/impl/Output.h>
#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/DisplayColorProfile.h>
+#include <compositionengine/mock/Layer.h>
+#include <compositionengine/mock/LayerFE.h>
+#include <compositionengine/mock/OutputLayer.h>
#include <compositionengine/mock/RenderSurface.h>
#include <gtest/gtest.h>
#include <ui/Rect.h>
@@ -267,5 +270,84 @@
EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false));
}
+/* ------------------------------------------------------------------------
+ * Output::getOutputLayerForLayer()
+ */
+
+TEST_F(OutputTest, getOutputLayerForLayerWorks) {
+ mock::OutputLayer* outputLayer1 = new StrictMock<mock::OutputLayer>();
+ mock::OutputLayer* outputLayer2 = new StrictMock<mock::OutputLayer>();
+
+ Output::OutputLayers outputLayers;
+ outputLayers.emplace_back(std::unique_ptr<OutputLayer>(outputLayer1));
+ outputLayers.emplace_back(nullptr);
+ outputLayers.emplace_back(std::unique_ptr<OutputLayer>(outputLayer2));
+ mOutput.setOutputLayersOrderedByZ(std::move(outputLayers));
+
+ StrictMock<mock::Layer> layer;
+ StrictMock<mock::Layer> otherLayer;
+
+ // If the input layer matches the first OutputLayer, it will be returned.
+ EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(layer));
+ EXPECT_EQ(outputLayer1, mOutput.getOutputLayerForLayer(&layer));
+
+ // If the input layer matches the second OutputLayer, it will be returned.
+ EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer));
+ EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(layer));
+ EXPECT_EQ(outputLayer2, mOutput.getOutputLayerForLayer(&layer));
+
+ // If the input layer does not match an output layer, null will be returned.
+ EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer));
+ EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(otherLayer));
+ EXPECT_EQ(nullptr, mOutput.getOutputLayerForLayer(&layer));
+}
+
+/* ------------------------------------------------------------------------
+ * Output::getOrCreateOutputLayer()
+ */
+
+TEST_F(OutputTest, getOrCreateOutputLayerWorks) {
+ mock::OutputLayer* existingOutputLayer = new StrictMock<mock::OutputLayer>();
+
+ Output::OutputLayers outputLayers;
+ outputLayers.emplace_back(nullptr);
+ outputLayers.emplace_back(std::unique_ptr<OutputLayer>(existingOutputLayer));
+ mOutput.setOutputLayersOrderedByZ(std::move(outputLayers));
+
+ std::shared_ptr<mock::Layer> layer{new StrictMock<mock::Layer>()};
+ sp<LayerFE> layerFE{new StrictMock<mock::LayerFE>()};
+
+ StrictMock<mock::Layer> otherLayer;
+
+ {
+ // If there is no OutputLayer corresponding to the input layer, a
+ // new OutputLayer is constructed and returned.
+ EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(otherLayer));
+ auto result = mOutput.getOrCreateOutputLayer(layer, layerFE);
+ EXPECT_NE(existingOutputLayer, result.get());
+ EXPECT_TRUE(result.get() != nullptr);
+ EXPECT_EQ(layer.get(), &result->getLayer());
+ EXPECT_EQ(layerFE.get(), &result->getLayerFE());
+
+ // The entries in the ordered array should be unchanged.
+ auto& outputLayers = mOutput.getOutputLayersOrderedByZ();
+ EXPECT_EQ(nullptr, outputLayers[0].get());
+ EXPECT_EQ(existingOutputLayer, outputLayers[1].get());
+ }
+
+ {
+ // If there is an existing OutputLayer for the requested layer, an owned
+ // pointer is returned
+ EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(*layer));
+ auto result = mOutput.getOrCreateOutputLayer(layer, layerFE);
+ EXPECT_EQ(existingOutputLayer, result.get());
+
+ // The corresponding entry in the ordered array should be cleared.
+ auto& outputLayers = mOutput.getOutputLayersOrderedByZ();
+ EXPECT_EQ(nullptr, outputLayers[0].get());
+ EXPECT_EQ(nullptr, outputLayers[1].get());
+ }
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 18c524f..7f451a5 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -21,10 +21,10 @@
#include <sys/types.h>
#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/impl/HwcBufferCache.h>
#include <gui/ConsumerBase.h>
#include "DisplayIdentification.h"
-#include "HWComposerBufferCache.h"
// ---------------------------------------------------------------------------
namespace android {
@@ -88,7 +88,7 @@
// Hardware composer, owned by SurfaceFlinger.
HWComposer& mHwc;
- HWComposerBufferCache mHwcBufferCache;
+ compositionengine::impl::HwcBufferCache mHwcBufferCache;
// Previous buffer to release after getting an updated retire fence
bool mHasPendingRelease;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 87ae7dd..d6543d1 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -21,11 +21,11 @@
#include <string>
#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/impl/HwcBufferCache.h>
#include <gui/ConsumerBase.h>
#include <gui/IGraphicBufferProducer.h>
#include "DisplayIdentification.h"
-#include "HWComposerBufferCache.h"
// ---------------------------------------------------------------------------
namespace android {
@@ -253,7 +253,7 @@
bool mMustRecompose;
- HWComposerBufferCache mHwcBufferCache;
+ compositionengine::impl::HwcBufferCache mHwcBufferCache;
bool mForceHwcCopy;
};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 619964f..185393e 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -46,6 +46,7 @@
#include <gui/Surface.h>
#include "BufferLayer.h"
+#include "ColorLayer.h"
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "Layer.h"
@@ -107,7 +108,6 @@
mCurrentState.cornerRadius = 0.0f;
mCurrentState.api = -1;
mCurrentState.hasColorTransform = false;
- mCurrentState.colorDataspace = ui::Dataspace::UNKNOWN;
// drawing state & current state are identical
mDrawingState = mCurrentState;
@@ -1106,6 +1106,11 @@
mNeedsFiltering = (!getActiveTransform(c).preserveRects() || type >= ui::Transform::SCALE);
}
+ if (mChildrenChanged) {
+ flags |= eVisibleRegion;
+ mChildrenChanged = false;
+ }
+
// If the layer is hidden, signal and clear out all local sync points so
// that transactions for layers depending on this layer's frames becoming
// visible are not blocked
@@ -1272,17 +1277,35 @@
return true;
}
-bool Layer::setColor(const half3& color) {
- if (color.r == mCurrentState.color.r && color.g == mCurrentState.color.g &&
- color.b == mCurrentState.color.b)
+bool Layer::setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace) {
+ if (!mCurrentState.bgColorLayer && alpha == 0) {
return false;
+ } else if (!mCurrentState.bgColorLayer && alpha != 0) {
+ // create background color layer if one does not yet exist
+ uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor;
+ const String8& name = mName + "BackgroundColorLayer";
+ mCurrentState.bgColorLayer =
+ new ColorLayer(LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, flags));
- mCurrentState.sequence++;
- mCurrentState.color.r = color.r;
- mCurrentState.color.g = color.g;
- mCurrentState.color.b = color.b;
- mCurrentState.modified = true;
- setTransactionFlags(eTransactionNeeded);
+ // add to child list
+ addChild(mCurrentState.bgColorLayer);
+ mFlinger->mLayersAdded = true;
+ // set up SF to handle added color layer
+ if (isRemovedFromCurrentState()) {
+ mCurrentState.bgColorLayer->onRemovedFromCurrentState();
+ }
+ mFlinger->setTransactionFlags(eTransactionNeeded);
+ } else if (mCurrentState.bgColorLayer && alpha == 0) {
+ mCurrentState.bgColorLayer->reparent(nullptr);
+ mCurrentState.bgColorLayer = nullptr;
+ return true;
+ }
+
+ mCurrentState.bgColorLayer->setColor(color);
+ mCurrentState.bgColorLayer->setLayer(std::numeric_limits<int32_t>::min());
+ mCurrentState.bgColorLayer->setAlpha(alpha);
+ mCurrentState.bgColorLayer->setDataspace(dataspace);
+
return true;
}
@@ -1610,13 +1633,16 @@
}
void Layer::addChild(const sp<Layer>& layer) {
+ mChildrenChanged = true;
+
mCurrentChildren.add(layer);
layer->setParent(this);
}
ssize_t Layer::removeChild(const sp<Layer>& layer) {
- layer->setParent(nullptr);
+ mChildrenChanged = true;
+ layer->setParent(nullptr);
return mCurrentChildren.remove(layer);
}
@@ -2227,6 +2253,10 @@
return mDrawingState.inputInfo.token != nullptr;
}
+std::shared_ptr<compositionengine::Layer> Layer::getCompositionLayer() const {
+ return nullptr;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 00e1a6f..4cead87 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -19,6 +19,7 @@
#include <sys/types.h>
+#include <compositionengine/LayerFE.h>
#include <gui/BufferQueue.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
@@ -51,7 +52,6 @@
#include "TransactionCompletedThread.h"
#include "DisplayHardware/HWComposer.h"
-#include "DisplayHardware/HWComposerBufferCache.h"
#include "RenderArea.h"
using namespace android::surfaceflinger;
@@ -68,6 +68,10 @@
class LayerDebugInfo;
class LayerBE;
+namespace compositionengine {
+class Layer;
+}
+
namespace impl {
class SurfaceInterceptor;
}
@@ -87,7 +91,7 @@
uint32_t flags;
};
-class Layer : public virtual RefBase {
+class Layer : public virtual compositionengine::LayerFE {
static std::atomic<int32_t> sSequence;
public:
@@ -205,7 +209,6 @@
// and the buffer state layer's children. Z order will be set to
// INT_MIN
sp<Layer> bgColorLayer;
- ui::Dataspace colorDataspace; // The dataspace of the background color layer
// The deque of callback handles for this frame. The back of the deque contains the most
// recent callback handle.
@@ -271,7 +274,7 @@
virtual bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
virtual bool setAlpha(float alpha);
- virtual bool setColor(const half3& color);
+ virtual bool setColor(const half3& /*color*/) { return false; };
// Set rounded corner radius for this layer and its children.
//
@@ -314,8 +317,7 @@
const std::vector<sp<CallbackHandle>>& /*handles*/) {
return false;
};
- virtual bool setColorAlpha(float /*alpha*/) { return false; };
- virtual bool setColorDataspace(ui::Dataspace /*dataspace*/) { return false; };
+ virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
@@ -326,6 +328,8 @@
// visually.
bool isLegacyDataSpace() const;
+ virtual std::shared_ptr<compositionengine::Layer> getCompositionLayer() const;
+
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
// one empty rect.
@@ -851,6 +855,8 @@
// Can only be accessed with the SF state lock held.
bool mLayerDetached{false};
+ // Can only be accessed with the SF state lock held.
+ bool mChildrenChanged{false};
private:
/**
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index 3f5134e..6270efa 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -19,6 +19,8 @@
#include <stdint.h>
#include <sys/types.h>
+#include <compositionengine/impl/HwcBufferCache.h>
+
#include <renderengine/Mesh.h>
#include <renderengine/RenderEngine.h>
#include <renderengine/Texture.h>
@@ -26,7 +28,6 @@
#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/HWComposer.h"
-#include "DisplayHardware/HWComposerBufferCache.h"
#include "SurfaceFlinger.h"
namespace android {
@@ -120,7 +121,7 @@
bool clearClientTarget;
Rect displayFrame;
FloatRect sourceCrop;
- HWComposerBufferCache bufferCache;
+ compositionengine::impl::HwcBufferCache bufferCache;
HWC2::Transform transform;
};
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 9b2a6fc..075e238 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -757,18 +757,7 @@
const uint32_t hwcLatency = 0;
// Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
- const nsecs_t nextRefresh = computeNextRefresh(hwcLatency);
-
- // The DispSync time is already adjusted for the difference between
- // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
- // we don't need to factor that in here. Pad a little to avoid
- // weird effects if apps might be requesting times right on the edge.
- nsecs_t extraPadding = 0;
- if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
- extraPadding = 1000000; // 1ms (6% of 60Hz)
- }
-
- return nextRefresh + extraPadding;
+ return computeNextRefresh(hwcLatency);
}
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
new file mode 100644
index 0000000..a0a4455
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2019 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 "PhaseOffsets.h"
+
+#include <cutils/properties.h>
+
+#include "SurfaceFlingerProperties.h"
+
+namespace android {
+using namespace android::sysprop;
+
+namespace scheduler {
+
+PhaseOffsets::~PhaseOffsets() = default;
+
+namespace impl {
+PhaseOffsets::PhaseOffsets() {
+ int64_t vsyncPhaseOffsetNs = vsync_event_phase_offset_ns(1000000);
+
+ int64_t sfVsyncPhaseOffsetNs = vsync_sf_event_phase_offset_ns(1000000);
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.early_phase_offset_ns", value, "-1");
+ const int earlySfOffsetNs = atoi(value);
+
+ property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
+ const int earlyGlSfOffsetNs = atoi(value);
+
+ property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
+ const int earlyAppOffsetNs = atoi(value);
+
+ property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
+ const int earlyGlAppOffsetNs = atoi(value);
+
+ property_get("debug.sf.high_fps_early_phase_offset_ns", value, "-1");
+ const int highFpsEarlySfOffsetNs = atoi(value);
+
+ property_get("debug.sf.high_fps_early_gl_phase_offset_ns", value, "-1");
+ const int highFpsEarlyGlSfOffsetNs = atoi(value);
+
+ property_get("debug.sf.high_fps_early_app_phase_offset_ns", value, "-1");
+ const int highFpsEarlyAppOffsetNs = atoi(value);
+
+ property_get("debug.sf.high_fps_early_gl_app_phase_offset_ns", value, "-1");
+ const int highFpsEarlyGlAppOffsetNs = atoi(value);
+
+ // TODO(b/122905996): Define these in device.mk.
+ property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "1000000");
+ const int highFpsLateAppOffsetNs = atoi(value);
+
+ property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "8000000");
+ const int highFpsLateSfOffsetNs = atoi(value);
+
+ mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs
+ : sfVsyncPhaseOffsetNs,
+ earlyAppOffsetNs != -1 ? earlyAppOffsetNs
+ : vsyncPhaseOffsetNs};
+ mDefaultRefreshRateOffsets.earlyGl = {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs
+ : sfVsyncPhaseOffsetNs,
+ earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs
+ : vsyncPhaseOffsetNs};
+ mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
+
+ mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
+ : highFpsLateAppOffsetNs,
+ highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
+ : highFpsLateSfOffsetNs};
+ mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
+ : highFpsLateAppOffsetNs,
+ highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
+ : highFpsLateSfOffsetNs};
+ mHighRefreshRateOffsets.late = {highFpsLateAppOffsetNs, highFpsLateSfOffsetNs};
+}
+
+PhaseOffsets::Offsets PhaseOffsets::getCurrentOffsets() const {
+ switch (mRefreshRateType) {
+ case RefreshRateConfigs::RefreshRateType::PERFORMANCE:
+ return mHighRefreshRateOffsets;
+ default:
+ return mDefaultRefreshRateOffsets;
+ }
+}
+
+void PhaseOffsets::dump(std::string& result) const {
+ const auto [early, earlyGl, late] = getCurrentOffsets();
+ base::StringAppendF(&result,
+ " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
+ " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
+ "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n",
+ late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf);
+}
+
+nsecs_t PhaseOffsets::getCurrentAppOffset() {
+ return getCurrentOffsets().late.app;
+}
+
+nsecs_t PhaseOffsets::getCurrentSfOffset() {
+ return getCurrentOffsets().late.sf;
+}
+
+} // namespace impl
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
new file mode 100644
index 0000000..cbcaade
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019 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 <cinttypes>
+
+#include "RefreshRateConfigs.h"
+#include "VSyncModulator.h"
+
+namespace android {
+namespace scheduler {
+
+/*
+ * This class encapsulates offsets for different refresh rates. Depending
+ * on what refresh rate we are using, and wheter we are composing in GL,
+ * different offsets will help us with latency. This class keeps track of
+ * which mode the device is on, and returns approprate offsets when needed.
+ */
+class PhaseOffsets {
+public:
+ struct Offsets {
+ VSyncModulator::Offsets early;
+ VSyncModulator::Offsets earlyGl;
+ VSyncModulator::Offsets late;
+ };
+
+ virtual ~PhaseOffsets();
+
+ virtual nsecs_t getCurrentAppOffset() = 0;
+ virtual nsecs_t getCurrentSfOffset() = 0;
+ virtual Offsets getCurrentOffsets() const = 0;
+ virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0;
+ virtual void dump(std::string& result) const = 0;
+};
+
+namespace impl {
+class PhaseOffsets : public scheduler::PhaseOffsets {
+public:
+ PhaseOffsets();
+
+ nsecs_t getCurrentAppOffset() override;
+ nsecs_t getCurrentSfOffset() override;
+
+ // Returns early, early GL, and late offsets for Apps and SF.
+ Offsets getCurrentOffsets() const override;
+
+ // This function should be called when the device is switching between different
+ // refresh rates, to properly update the offsets.
+ void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) override {
+ mRefreshRateType = refreshRateType;
+ }
+
+ // Returns current offsets in human friendly format.
+ void dump(std::string& result) const override;
+
+private:
+ Offsets getmDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; }
+ Offsets getmHighRefreshRateOffsets() { return mHighRefreshRateOffsets; }
+
+ std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType =
+ RefreshRateConfigs::RefreshRateType::DEFAULT;
+
+ Offsets mDefaultRefreshRateOffsets;
+ Offsets mHighRefreshRateOffsets;
+};
+} // namespace impl
+
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index bfe5da5..026f7c7 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -47,6 +47,8 @@
int configId;
// Human readable name of the refresh rate.
std::string name;
+ // Refresh rate in frames per second, rounded to the nearest integer.
+ uint32_t fps = 0;
};
// TODO(b/122916473): Get this information from configs prepared by vendors, instead of
@@ -63,7 +65,7 @@
void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
// This is the rate that HWC encapsulates right now when the device is in DOZE mode.
mRefreshRates.push_back(
- RefreshRate{RefreshRateType::POWER_SAVING, SCREEN_OFF_CONFIG_ID, "ScreenOff"});
+ RefreshRate{RefreshRateType::POWER_SAVING, SCREEN_OFF_CONFIG_ID, "ScreenOff", 0});
if (configs.size() < 1) {
ALOGE("Device does not have valid configs. Config size is 0.");
@@ -86,10 +88,11 @@
nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second;
if (vsyncPeriod != 0) {
const float fps = 1e9 / vsyncPeriod;
- mRefreshRates.push_back(RefreshRate{RefreshRateType::DEFAULT,
- configIdToVsyncPeriod[0].first,
- base::StringPrintf("%2.ffps", fps)});
+ mRefreshRates.push_back(
+ RefreshRate{RefreshRateType::DEFAULT, configIdToVsyncPeriod[0].first,
+ base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)});
}
+
if (configs.size() < 2) {
return;
}
@@ -99,9 +102,9 @@
vsyncPeriod = configIdToVsyncPeriod[1].second;
if (vsyncPeriod != 0) {
const float fps = 1e9 / vsyncPeriod;
- mRefreshRates.push_back(RefreshRate{RefreshRateType::PERFORMANCE,
- configIdToVsyncPeriod[1].first,
- base::StringPrintf("%2.ffps", fps)});
+ mRefreshRates.push_back(
+ RefreshRate{RefreshRateType::PERFORMANCE, configIdToVsyncPeriod[1].first,
+ base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)});
}
}
@@ -109,4 +112,4 @@
};
} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index 7e22232..dcb2988 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -20,6 +20,7 @@
#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/SchedulerUtils.h"
+#include "TimeStats/TimeStats.h"
#include "android-base/stringprintf.h"
#include "utils/Timers.h"
@@ -41,8 +42,10 @@
public:
explicit RefreshRateStats(
- const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs)
+ const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
+ const std::shared_ptr<TimeStats>& timeStats)
: mRefreshRateConfigs(std::make_unique<RefreshRateConfigs>(configs)),
+ mTimeStats(timeStats),
mPreviousRecordedTime(systemTime()) {}
~RefreshRateStats() = default;
@@ -116,10 +119,16 @@
// this method was called.
void flushTimeForMode(int mode) {
nsecs_t currentTime = systemTime();
- int64_t timeElapsedMs = ns2ms(currentTime - mPreviousRecordedTime);
+ nsecs_t timeElapsed = currentTime - mPreviousRecordedTime;
+ int64_t timeElapsedMs = ns2ms(timeElapsed);
mPreviousRecordedTime = currentTime;
mConfigModesTotalTime[mode] += timeElapsedMs;
+ for (const auto& config : mRefreshRateConfigs->getRefreshRates()) {
+ if (config.configId == mode) {
+ mTimeStats->recordRefreshRate(config.fps, timeElapsed);
+ }
+ }
}
// Formats the time in milliseconds into easy to read format.
@@ -136,6 +145,9 @@
// Keeps information about refresh rate configs that device has.
std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
+ // Aggregate refresh rate statistics for telemetry.
+ std::shared_ptr<TimeStats> mTimeStats;
+
int64_t mCurrentConfigMode = 0;
int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
@@ -145,4 +157,4 @@
};
} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index b003451..00820f1 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -70,7 +70,7 @@
mEventControlThread = std::make_unique<impl::EventControlThread>(function);
char value[PROPERTY_VALUE_MAX];
- property_get("debug.sf.set_idle_timer_ms", value, "0");
+ property_get("debug.sf.set_idle_timer_ms", value, "30");
mSetIdleTimerMs = atoi(value);
if (mSetIdleTimerMs > 0) {
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index dde0c57..d7ec733 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -18,9 +18,10 @@
#include <utils/Errors.h>
+#include <cinttypes>
#include <mutex>
-using namespace android::surfaceflinger;
+#include "Scheduler.h"
namespace android {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ee202a3..cf2b80c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -40,6 +40,8 @@
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/OutputLayer.h>
#include <compositionengine/RenderSurface.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <dvr/vr_flinger.h>
@@ -211,8 +213,6 @@
constexpr float kSrgbWhiteZ = 1.0891f;
// ---------------------------------------------------------------------------
-int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
-int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
bool SurfaceFlinger::useHwcForRgbToYuv;
uint64_t SurfaceFlinger::maxVirtualDisplaySize;
@@ -273,6 +273,7 @@
mLayersRemoved(false),
mLayersAdded(false),
mBootTime(systemTime()),
+ mPhaseOffsets{getFactory().createPhaseOffsets()},
mVisibleRegionsDirty(false),
mGeometryInvalid(false),
mAnimCompositionPending(false),
@@ -298,10 +299,6 @@
: SurfaceFlinger(factory, SkipInitialization) {
ALOGI("SurfaceFlinger is starting");
- vsyncPhaseOffsetNs = vsync_event_phase_offset_ns(1000000);
-
- sfVsyncPhaseOffsetNs = vsync_sf_event_phase_offset_ns(1000000);
-
hasSyncFramework = running_without_sync_framework(true);
dispSyncPresentTimeOffset = present_time_offset_from_vsync_ns(0);
@@ -400,29 +397,11 @@
auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
- property_get("debug.sf.early_phase_offset_ns", value, "-1");
- const int earlySfOffsetNs = atoi(value);
-
- property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
- const int earlyGlSfOffsetNs = atoi(value);
-
- property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
- const int earlyAppOffsetNs = atoi(value);
-
- property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
- const int earlyGlAppOffsetNs = atoi(value);
-
property_get("debug.sf.use_scheduler", value, "0");
mUseScheduler = atoi(value);
- const VSyncModulator::Offsets earlyOffsets =
- {earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
- earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
- const VSyncModulator::Offsets earlyGlOffsets =
- {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
- earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
- mVsyncModulator.setPhaseOffsets(earlyOffsets, earlyGlOffsets,
- {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs});
+ const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+ mVsyncModulator.setPhaseOffsets(early, gl, late);
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
@@ -629,7 +608,7 @@
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);
+ ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset());
Mutex::Autolock _l(mStateLock);
@@ -640,13 +619,17 @@
mScheduler = getFactory().createScheduler([this](bool enabled) {
setVsyncEnabled(EventThread::DisplayType::Primary, enabled);
});
+ // TODO(b/113612090): Currently we assume that if scheduler is turned on, then the refresh
+ // rate is 90. Once b/122905403 is completed, this should be updated accordingly.
+ mPhaseOffsets->setRefreshRateType(
+ scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
mAppConnectionHandle =
- mScheduler->createConnection("appConnection", SurfaceFlinger::vsyncPhaseOffsetNs,
+ mScheduler->createConnection("appConnection", mPhaseOffsets->getCurrentAppOffset(),
resyncCallback,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
- mScheduler->createConnection("sfConnection", SurfaceFlinger::sfVsyncPhaseOffsetNs,
+ mScheduler->createConnection("sfConnection", mPhaseOffsets->getCurrentSfOffset(),
resyncCallback, [this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
@@ -657,14 +640,14 @@
} else {
mEventThreadSource =
std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
- SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
+ mPhaseOffsets->getCurrentAppOffset(), true, "app");
mEventThread =
std::make_unique<impl::EventThread>(mEventThreadSource.get(),
impl::EventThread::InterceptVSyncsCallback(),
"appEventThread");
mSfEventThreadSource =
std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
- SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
+ mPhaseOffsets->getCurrentSfOffset(), true, "sf");
mSFEventThread =
std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
@@ -745,10 +728,24 @@
}
if (mUseScheduler) {
- mScheduler->setExpiredIdleTimerCallback([this]() { setRefreshRateTo(60.f /* fps */); });
- mScheduler->setResetIdleTimerCallback([this]() { setRefreshRateTo(90.f /* fps */); });
- mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(
- getHwComposer().getConfigs(*display->getId()));
+ mScheduler->setExpiredIdleTimerCallback([this]() {
+ mPhaseOffsets->setRefreshRateType(
+ scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT);
+ const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+ mVsyncModulator.setPhaseOffsets(early, gl, late);
+ setRefreshRateTo(60.f /* fps */);
+ });
+ mScheduler->setResetIdleTimerCallback([this]() {
+ mPhaseOffsets->setRefreshRateType(
+ scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
+ const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+ mVsyncModulator.setPhaseOffsets(early, gl, late);
+ setRefreshRateTo(90.f /* fps */);
+ });
+ mRefreshRateStats =
+ std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
+ *display->getId()),
+ mTimeStats);
}
ALOGV("Done initializing");
@@ -901,7 +898,7 @@
info.xdpi = xdpi;
info.ydpi = ydpi;
info.fps = 1e9 / hwConfig->getVsyncPeriod();
- info.appVsyncOffset = vsyncPhaseOffsetNs;
+ info.appVsyncOffset = mPhaseOffsets->getCurrentAppOffset();
// This is how far in advance a buffer must be queued for
// presentation at a given time. If you want a buffer to appear
@@ -915,8 +912,8 @@
//
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
- info.presentationDeadline = hwConfig->getVsyncPeriod() -
- sfVsyncPhaseOffsetNs + 1000000;
+ info.presentationDeadline =
+ hwConfig->getVsyncPeriod() - mPhaseOffsets->getCurrentSfOffset() + 1000000;
// All non-virtual displays are currently considered secure.
info.secure = true;
@@ -1966,11 +1963,11 @@
nsecs_t compositeToPresentLatency) {
// Integer division and modulo round toward 0 not -inf, so we need to
// treat negative and positive offsets differently.
- nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0)
- ? (stats.vsyncPeriod - (sfVsyncPhaseOffsetNs % stats.vsyncPeriod))
- : ((-sfVsyncPhaseOffsetNs) % stats.vsyncPeriod);
+ nsecs_t idealLatency = (mPhaseOffsets->getCurrentSfOffset() > 0)
+ ? (stats.vsyncPeriod - (mPhaseOffsets->getCurrentSfOffset() % stats.vsyncPeriod))
+ : ((-mPhaseOffsets->getCurrentSfOffset()) % stats.vsyncPeriod);
- // Just in case sfVsyncPhaseOffsetNs == -vsyncInterval.
+ // Just in case mPhaseOffsets->getCurrentSfOffset() == -vsyncInterval.
if (idealLatency <= 0) {
idealLatency = stats.vsyncPeriod;
}
@@ -1979,7 +1976,7 @@
// composition and present times, which often have >1ms of jitter.
// Reducing jitter is important if an app attempts to extrapolate
// something (such as user input) to an accurate diasplay time.
- // Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
+ // Snapping also allows an app to precisely calculate mPhaseOffsets->getCurrentSfOffset()
// with (presentLatency % interval).
nsecs_t bias = stats.vsyncPeriod / 2;
int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod;
@@ -2257,7 +2254,8 @@
const auto& displayState = display->getState();
Region opaqueRegion;
Region dirtyRegion;
- Vector<sp<Layer>> layersSortedByZ;
+ compositionengine::Output::OutputLayers layersSortedByZ;
+ Vector<sp<Layer>> deprecated_layersSortedByZ;
Vector<sp<Layer>> layersNeedingFences;
const ui::Transform& tr = displayState.transform;
const Rect bounds = displayState.bounds;
@@ -2265,15 +2263,27 @@
computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
mDrawingState.traverseInZOrder([&](Layer* layer) {
+ auto compositionLayer = layer->getCompositionLayer();
+ if (compositionLayer == nullptr) {
+ return;
+ }
+
bool hwcLayerDestroyed = false;
const auto displayId = displayDevice->getId();
+ sp<compositionengine::LayerFE> layerFE = compositionLayer->getLayerFE();
+ LOG_ALWAYS_FATAL_IF(layerFE.get() == nullptr);
+
if (display->belongsInOutput(layer->getLayerStack(),
layer->getPrimaryDisplayOnly())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
if (!drawRegion.isEmpty()) {
- layersSortedByZ.add(layer);
+ layersSortedByZ.emplace_back(
+ display->getOrCreateOutputLayer(layer->getCompositionLayer(),
+ layerFE));
+
+ deprecated_layersSortedByZ.add(layer);
} else {
// Clear out the HWC layer if this layer was
// previously visible, but no longer is
@@ -2299,7 +2309,10 @@
}
});
}
- displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
+
+ display->setOutputLayersOrderedByZ(std::move(layersSortedByZ));
+
+ displayDevice->setVisibleLayersSortedByZ(deprecated_layersSortedByZ);
displayDevice->setLayersNeedingFences(layersNeedingFences);
Region undefinedRegion{bounds};
@@ -3861,17 +3874,16 @@
if (layer->setColor(s.color))
flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eColorAlphaChanged) {
- if (layer->setColorAlpha(s.colorAlpha)) flags |= eTraversalNeeded;
- }
- if (what & layer_state_t::eColorDataspaceChanged) {
- if (layer->setColorDataspace(s.colorDataspace)) flags |= eTraversalNeeded;
- }
if (what & layer_state_t::eColorTransformChanged) {
if (layer->setColorTransform(s.colorTransform)) {
flags |= eTraversalNeeded;
}
}
+ if (what & layer_state_t::eBackgroundColorChanged) {
+ if (layer->setBackgroundColor(s.color, s.bgColorAlpha, s.bgColorDataspace)) {
+ flags |= eTraversalNeeded;
+ }
+ }
if (what & layer_state_t::eMatrixChanged) {
// TODO: b/109894387
//
@@ -4520,15 +4532,10 @@
}
void SurfaceFlinger::dumpVSync(std::string& result) const {
- const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
- const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
+ mPhaseOffsets->dump(result);
StringAppendF(&result,
- " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
- " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
- "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
" present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
- vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, appEarlyOffset, sfEarlyOffset,
- appEarlyGlOffset, sfEarlyGlOffset, dispSyncPresentTimeOffset, getVsyncPeriod());
+ dispSyncPresentTimeOffset, getVsyncPeriod());
StringAppendF(&result, "Scheduler: %s\n\n", mUseScheduler ? "enabled" : "disabled");
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index dfb01fb..9aaf6de 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -59,6 +59,7 @@
#include "Scheduler/DispSync.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/MessageQueue.h"
+#include "Scheduler/PhaseOffsets.h"
#include "Scheduler/RefreshRateStats.h"
#include "Scheduler/Scheduler.h"
#include "Scheduler/VSyncModulator.h"
@@ -952,7 +953,10 @@
std::unique_ptr<EventControlThread> mEventControlThread;
std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
+ // Calculates correct offsets.
VSyncModulator mVsyncModulator;
+ // Keeps track of all available phase offsets for different refresh types.
+ std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets;
// Can only accessed from the main thread, these members
// don't need synchronization
@@ -996,7 +1000,7 @@
std::unique_ptr<SurfaceInterceptor> mInterceptor{mFactory.createSurfaceInterceptor(this)};
SurfaceTracing mTracing;
LayerStats mLayerStats;
- std::unique_ptr<TimeStats> mTimeStats;
+ std::shared_ptr<TimeStats> mTimeStats;
bool mUseHwcVirtualDisplays = false;
std::atomic<uint32_t> mFrameMissedCount{0};
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index 77679e3..26d2c21 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -33,6 +33,7 @@
#include "Scheduler/DispSync.h"
#include "Scheduler/EventControlThread.h"
#include "Scheduler/MessageQueue.h"
+#include "Scheduler/PhaseOffsets.h"
#include "Scheduler/Scheduler.h"
#include "TimeStats/TimeStats.h"
@@ -68,6 +69,10 @@
return std::make_unique<android::impl::MessageQueue>();
}
+ std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override {
+ return std::make_unique<scheduler::impl::PhaseOffsets>();
+ }
+
std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) override {
return std::make_unique<Scheduler>(callback);
}
@@ -123,8 +128,8 @@
return new ColorLayer(args);
}
- std::unique_ptr<TimeStats> createTimeStats() override {
- return std::make_unique<TimeStats>();
+ std::shared_ptr<TimeStats> createTimeStats() override {
+ return std::make_shared<android::impl::TimeStats>();
}
};
static Factory factory;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index f747684..fc1d0f8 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -52,6 +52,10 @@
namespace compositionengine {
class CompositionEngine;
} // namespace compositionengine
+
+namespace scheduler {
+class PhaseOffsets;
+} // namespace scheduler
namespace surfaceflinger {
class NativeWindowSurface;
@@ -66,6 +70,7 @@
std::function<void(bool)> setVSyncEnabled) = 0;
virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
+ virtual std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() = 0;
virtual std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) = 0;
virtual std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
@@ -88,7 +93,7 @@
virtual sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) = 0;
virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
- virtual std::unique_ptr<TimeStats> createTimeStats() = 0;
+ virtual std::shared_ptr<TimeStats> createTimeStats() = 0;
protected:
~Factory() = default;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 8d3776b..78c6e74 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -32,6 +32,8 @@
namespace android {
+namespace impl {
+
void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
ATRACE_CALL();
@@ -450,6 +452,15 @@
mPowerTime.powerMode = powerMode;
}
+void TimeStats::recordRefreshRate(uint32_t fps, nsecs_t duration) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mTimeStats.refreshRateStats.count(fps)) {
+ mTimeStats.refreshRateStats[fps] += duration;
+ } else {
+ mTimeStats.refreshRateStats.insert({fps, duration});
+ }
+}
+
void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
ATRACE_CALL();
@@ -547,6 +558,7 @@
mTimeStats.clientCompositionFrames = 0;
mTimeStats.displayOnTime = 0;
mTimeStats.presentToPresent.hist.clear();
+ mTimeStats.refreshRateStats.clear();
mPowerTime.prevTime = systemTime();
mGlobalRecord.prevPresentTime = 0;
mGlobalRecord.presentFences.clear();
@@ -580,4 +592,6 @@
}
}
+} // namespace impl
+
} // namespace android
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index e8fbcab..d8c0786 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -36,6 +36,40 @@
namespace android {
class TimeStats {
+public:
+ virtual ~TimeStats() = default;
+
+ virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
+ virtual bool isEnabled() = 0;
+
+ virtual void incrementTotalFrames() = 0;
+ virtual void incrementMissedFrames() = 0;
+ virtual void incrementClientCompositionFrames() = 0;
+
+ virtual void setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
+ nsecs_t postTime) = 0;
+ virtual void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime) = 0;
+ virtual void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime) = 0;
+ virtual void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime) = 0;
+ virtual void setAcquireFence(int32_t layerID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& acquireFence) = 0;
+ virtual void setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime) = 0;
+ virtual void setPresentFence(int32_t layerID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& presentFence) = 0;
+ // Clean up the layer record
+ virtual void onDestroy(int32_t layerID) = 0;
+ // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
+ virtual void removeTimeRecord(int32_t layerID, uint64_t frameNumber) = 0;
+
+ virtual void setPowerMode(int32_t powerMode) = 0;
+ // Source of truth is RefrehRateStats.
+ virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0;
+ virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0;
+};
+
+namespace impl {
+
+class TimeStats : public android::TimeStats {
struct FrameTime {
uint64_t frameNumber = 0;
nsecs_t postTime = 0;
@@ -75,32 +109,33 @@
public:
TimeStats() = default;
- ~TimeStats() = default;
- void parseArgs(bool asProto, const Vector<String16>& args, std::string& result);
- bool isEnabled();
+ void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
+ bool isEnabled() override;
- void incrementTotalFrames();
- void incrementMissedFrames();
- void incrementClientCompositionFrames();
+ void incrementTotalFrames() override;
+ void incrementMissedFrames() override;
+ void incrementClientCompositionFrames() override;
void setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
- nsecs_t postTime);
- void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime);
- void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime);
- void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime);
+ nsecs_t postTime) override;
+ void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime) override;
+ void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime) override;
+ void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime) override;
void setAcquireFence(int32_t layerID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& acquireFence);
- void setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime);
+ const std::shared_ptr<FenceTime>& acquireFence) override;
+ void setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime) override;
void setPresentFence(int32_t layerID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& presentFence);
+ const std::shared_ptr<FenceTime>& presentFence) override;
// Clean up the layer record
- void onDestroy(int32_t layerID);
+ void onDestroy(int32_t layerID) override;
// If SF skips or rejects a buffer, remove the corresponding TimeRecord.
- void removeTimeRecord(int32_t layerID, uint64_t frameNumber);
+ void removeTimeRecord(int32_t layerID, uint64_t frameNumber) override;
- void setPowerMode(int32_t powerMode);
- void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence);
+ void setPowerMode(int32_t powerMode) override;
+ // Source of truth is RefrehRateStats.
+ void recordRefreshRate(uint32_t fps, nsecs_t duration) override;
+ void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) override;
// TODO(zzyiwei): Bound the timeStatsTracker with weighted LRU
// static const size_t MAX_NUM_LAYER_RECORDS = 200;
@@ -126,4 +161,6 @@
GlobalRecord mGlobalRecord;
};
+} // namespace impl
+
} // namespace android
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 75ce4be..16d2da0 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -103,6 +103,11 @@
StringAppendF(&result, "missedFrames = %d\n", missedFrames);
StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
+ StringAppendF(&result, "displayConfigStats is as below:\n");
+ for (const auto& [fps, duration] : refreshRateStats) {
+ StringAppendF(&result, "%dfps=%ldms ", fps, ns2ms(duration));
+ }
+ result.back() = '\n';
StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
StringAppendF(&result, "presentToPresent histogram is as below:\n");
result.append(presentToPresent.toString());
@@ -141,6 +146,13 @@
globalProto.set_missed_frames(missedFrames);
globalProto.set_client_composition_frames(clientCompositionFrames);
globalProto.set_display_on_time(displayOnTime);
+ for (const auto& ele : refreshRateStats) {
+ SFTimeStatsDisplayConfigBucketProto* configBucketProto =
+ globalProto.add_display_config_stats();
+ SFTimeStatsDisplayConfigProto* configProto = configBucketProto->mutable_config();
+ configProto->set_fps(ele.first);
+ configBucketProto->set_duration_millis(ns2ms(ele.second));
+ }
for (const auto& histEle : presentToPresent.hist) {
SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present();
histProto->set_time_millis(histEle.first);
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 5f40a1a..f2ac7ff 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -16,6 +16,7 @@
#pragma once
#include <timestatsproto/TimeStatsProtoHeader.h>
+#include <utils/Timers.h>
#include <optional>
#include <string>
@@ -61,6 +62,7 @@
int64_t displayOnTime = 0;
Histogram presentToPresent;
std::unordered_map<std::string, TimeStatsLayer> stats;
+ std::unordered_map<uint32_t, nsecs_t> refreshRateStats;
std::string toString(std::optional<uint32_t> maxLayers) const;
SFTimeStatsGlobalProto toProto(std::optional<uint32_t> maxLayers) const;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
index 377612a..0dacbeb 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
+++ b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
@@ -25,7 +25,7 @@
// changes to these messages, and keep google3 side proto messages in sync if
// the end to end pipeline needs to be updated.
-// Next tag: 9
+// Next tag: 10
message SFTimeStatsGlobalProto {
// The stats start time in UTC as seconds since January 1, 1970
optional int64 stats_start = 1;
@@ -39,6 +39,8 @@
optional int32 client_composition_frames = 5;
// Primary display on time in milliseconds.
optional int64 display_on_time = 7;
+ // Stats per display configuration.
+ repeated SFTimeStatsDisplayConfigBucketProto display_config_stats = 9;
// Present to present histogram.
repeated SFTimeStatsHistogramBucketProto present_to_present = 8;
// Stats per layer. Apps could have multiple layers.
@@ -80,3 +82,18 @@
// Number of frames in the bucket.
optional int32 frame_count = 2;
}
+
+// Next tag: 3
+message SFTimeStatsDisplayConfigBucketProto {
+ // Metadata desribing a display config.
+ optional SFTimeStatsDisplayConfigProto config = 1;
+ // Duration in milliseconds for how long the display was in this
+ // configuration.
+ optional int64 duration_millis = 2;
+}
+
+// Next tag: 2
+message SFTimeStatsDisplayConfigProto {
+ // Frames per second, rounded to the nearest integer.
+ optional int32 fps = 1;
+}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 56d3bd4..4f0ded3 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -675,6 +675,8 @@
void setRelativeZBasicHelper(uint32_t layerType);
void setRelativeZGroupHelper(uint32_t layerType);
void setAlphaBasicHelper(uint32_t layerType);
+ void setBackgroundColorHelper(uint32_t layerType, bool priorColor, bool bufferFill, float alpha,
+ Color finalColor);
protected:
LayerRenderPathTestHarness mHarness;
@@ -1330,92 +1332,6 @@
getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
}
-TEST_P(LayerRenderTypeTransactionTest, SetColorAlpha_Color_NoEffect) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 0, 0, ISurfaceComposerClient::eFXSurfaceColor));
-
- half3 color;
- color.r = 1.0f;
- color.g = 0.0f;
- color.b = 0.0f;
- Transaction()
- .setCrop_legacy(layer, Rect(0, 0, 32, 32))
- .setAlpha(layer, 1.0f)
- .setColor(layer, color)
- .setColorAlpha(layer, 0.5f)
- .apply();
-
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorAlpha_BufferQueue_NoEffect) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- Transaction().setAlpha(layer, 1.0f).setColorAlpha(layer, 0.5f).apply();
-
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorAlpha_BufferState_ColorLayer) {
- sp<SurfaceControl> bgLayer;
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(bgLayer = createLayer("test bg", 32, 32));
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bgLayer, Color::RED, 32, 32));
-
- // create color layer
- half3 color;
- color.r = 0.0f;
- color.g = 1.0f;
- color.b = 0.0f;
- Transaction().setFrame(layer, Rect(0, 0, 32, 32)).setColor(layer, color).apply();
-
- {
- SCOPED_TRACE("before alpha");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- // apply alpha
- Transaction().setAlpha(layer, 0.0f).apply();
- {
- SCOPED_TRACE("set alpha");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorAlpha_BufferState_NoColorLayer) {
- sp<SurfaceControl> bgLayer;
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(bgLayer = createLayer("test bg", 32, 32));
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bgLayer, Color::RED, 32, 32));
-
- {
- SCOPED_TRACE("before alpha");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- // setting alpha without creating color layer should have no effect
- Transaction().setFrame(layer, Rect(0, 0, 32, 32)).setAlpha(layer, 0.5f).apply();
- {
- SCOPED_TRACE("alpha");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
- }
-}
-
void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) {
sp<SurfaceControl> layer1;
sp<SurfaceControl> layer2;
@@ -1567,75 +1483,190 @@
}
}
-TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferState_NoPriorColor) {
- sp<SurfaceControl> bufferQueueLayer;
- sp<SurfaceControl> bufferStateLayer;
- ASSERT_NO_FATAL_FAILURE(bufferQueueLayer = createLayer("test bg", 32, 32));
- ASSERT_NO_FATAL_FAILURE(
- bufferStateLayer =
- createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+// RED: Color layer base color and BufferQueueLayer/BufferStateLayer fill
+// BLUE: prior background color
+// GREEN: final background color
+// BLACK: no color or fill
+void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType, bool priorColor,
+ bool bufferFill, float alpha,
+ Color finalColor) {
+ sp<SurfaceControl> layer;
+ int32_t width = 500;
+ int32_t height = 500;
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferQueueLayer, Color::RED, 32, 32));
-
- {
- SCOPED_TRACE("default color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ Color fillColor = Color::RED;
+ Color priorBgColor = Color::BLUE;
+ Color expectedColor = Color::BLACK;
+ switch (layerType) {
+ case ISurfaceComposerClient::eFXSurfaceColor:
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType));
+ Transaction()
+ .setCrop_legacy(layer, Rect(0, 0, width, height))
+ .setColor(layer, half3(1.0f, 0, 0))
+ .apply();
+ expectedColor = fillColor;
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
+ if (bufferFill) {
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, fillColor, width, height));
+ expectedColor = fillColor;
+ }
+ Transaction().setCrop_legacy(layer, Rect(0, 0, width, height)).apply();
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, layerType));
+ if (bufferFill) {
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height));
+ expectedColor = fillColor;
+ }
+ Transaction().setFrame(layer, Rect(0, 0, width, height)).apply();
+ break;
+ default:
+ GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper";
+ return;
}
- half3 color;
- color.r = 0.0f;
- color.g = 1.0f;
- color.b = 0.0f;
+ if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceColor) {
+ Transaction()
+ .setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN)
+ .apply();
+ if (!bufferFill) {
+ expectedColor = priorBgColor;
+ }
+ }
+
+ {
+ SCOPED_TRACE("default before setting background color layer");
+ screenshot()->expectColor(Rect(0, 0, width, height), expectedColor);
+ }
+
Transaction()
- .setFrame(bufferStateLayer, Rect(0, 0, 32, 32))
- .setLayer(bufferStateLayer, mLayerZBase + 1)
- .setColor(bufferStateLayer, color)
+ .setBackgroundColor(layer, half3(0, 1.0f, 0), alpha, ui::Dataspace::UNKNOWN)
.apply();
{
- SCOPED_TRACE("set color");
auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ shot->expectColor(Rect(0, 0, width, height), finalColor);
+ shot->expectBorder(Rect(0, 0, width, height), Color::BLACK);
}
}
-TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferState_PriorColor) {
- sp<SurfaceControl> bufferQueueLayer;
- sp<SurfaceControl> bufferStateLayer;
- ASSERT_NO_FATAL_FAILURE(bufferQueueLayer = createLayer("test bg", 32, 32));
- ASSERT_NO_FATAL_FAILURE(
- bufferStateLayer =
- createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceColor,
+ priorColor, bufferFill, alpha, finalColor));
+}
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferQueueLayer, Color::RED, 32, 32));
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_BufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = true;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
- half3 color;
- color.r = 0.0f;
- color.g = 1.0f;
- color.b = 0.0f;
- Transaction()
- .setFrame(bufferStateLayer, Rect(0, 0, 32, 32))
- .setLayer(bufferStateLayer, mLayerZBase + 1)
- .setColor(bufferStateLayer, color)
- .apply();
- {
- SCOPED_TRACE("default color");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
- }
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_NoBufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
- color.r = 0.0f;
- color.g = 0.0f;
- color.b = 1.0f;
- Transaction().setColor(bufferStateLayer, color).apply();
- {
- SCOPED_TRACE("new color");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
- }
+TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_BufferFill_PriorColor_Basic) {
+ bool priorColor = true;
+ bool bufferFill = true;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_NoBufferFill_PriorColor_Basic) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_NoPriorColor_ZeroAlpha_NoEffect) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_PriorColor_ZeroAlpha_DeleteBackground) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_BufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = true;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_NoBufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_NoBufferFill_PriorColor_Basic) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_NoPriorColor_ZeroAlpha_NoEffect) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_PriorColor_ZeroAlpha_DeleteBackground) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
}
TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) {
@@ -2491,71 +2522,6 @@
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_P(LayerRenderTypeTransactionTest, SetColorDataspace_ColorLayer_NoEffect) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 0, 0, ISurfaceComposerClient::eFXSurfaceColor));
- half3 color;
- color.r = 1.0f;
- color.g = 0.0f;
- color.b = 0.0f;
- Transaction()
- .setCrop_legacy(layer, Rect(0, 0, 32, 32))
- .setColor(layer, color)
- .setDataspace(layer, ui::Dataspace::UNKNOWN)
- .setColorDataspace(layer, ui::Dataspace::BT2020_ITU)
- .apply();
-
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorDataspace_BufferQueue_NoEffect) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- Transaction()
- .setDataspace(layer, ui::Dataspace::UNKNOWN)
- .setColorDataspace(layer, ui::Dataspace::BT2020_ITU)
- .apply();
-
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorDataspace_BufferState_ColorLayer) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- half3 color;
- color.r = 1.0f;
- color.g = 0.0f;
- color.b = 0.0f;
- Transaction()
- .setFrame(layer, Rect(0, 0, 32, 32))
- .setColor(layer, color)
- .setColorDataspace(layer, ui::Dataspace::BT2020_ITU)
- .apply();
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorDataspace_BufferState_NoColorLayer) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
- Transaction()
- .setFrame(layer, Rect(0, 0, 32, 32))
- .setDataspace(layer, ui::Dataspace::UNKNOWN)
- .setColorDataspace(layer, ui::Dataspace::DCI_P3)
- .apply();
-
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index a2c0611..68cf61e 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -31,6 +31,7 @@
"libutils",
],
static_libs: [
+ "libcompositionengine",
"libgmock",
"librenderengine",
"libtrace_proto",
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index b2bcb45..b1d45f39 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -58,6 +58,7 @@
"mock/MockMessageQueue.cpp",
"mock/MockNativeWindowSurface.cpp",
"mock/MockSurfaceInterceptor.cpp",
+ "mock/MockTimeStats.cpp",
"mock/system/window/MockNativeWindow.cpp",
],
static_libs: [
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
new file mode 100644
index 0000000..0739f15
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 <gmock/gmock.h>
+
+#include "Scheduler/PhaseOffsets.h"
+
+namespace android {
+namespace scheduler {
+
+class FakePhaseOffsets : public android::scheduler::PhaseOffsets {
+ nsecs_t FAKE_PHASE_OFFSET_NS = 0;
+
+public:
+ FakePhaseOffsets() = default;
+ ~FakePhaseOffsets() = default;
+
+ nsecs_t getCurrentAppOffset() override { return FAKE_PHASE_OFFSET_NS; }
+ nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; }
+
+ // Returns early, early GL, and late offsets for Apps and SF.
+ PhaseOffsets::Offsets getCurrentOffsets() const override {
+ return Offsets{{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
+ }
+
+ // This function should be called when the device is switching between different
+ // refresh rates, to properly update the offsets.
+ void setRefreshRateType(RefreshRateConfigs::RefreshRateType /*refreshRateType*/) override {}
+
+ // Returns current offsets in human friendly format.
+ void dump(std::string& /*result*/) const override {}
+};
+
+} // namespace scheduler
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 0384d9d..3d887ea 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -23,8 +23,10 @@
#include "Scheduler/RefreshRateStats.h"
#include "mock/DisplayHardware/MockDisplay.h"
+#include "mock/MockTimeStats.h"
using namespace std::chrono_literals;
+using testing::_;
namespace android {
namespace scheduler {
@@ -42,6 +44,7 @@
void init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs);
std::unique_ptr<RefreshRateStats> mRefreshRateStats;
+ std::shared_ptr<android::mock::TimeStats> mTimeStats;
};
RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -57,7 +60,8 @@
}
void RefreshRateStatsTest::init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs) {
- mRefreshRateStats = std::make_unique<RefreshRateStats>(configs);
+ mTimeStats = std::make_shared<android::mock::TimeStats>();
+ mRefreshRateStats = std::make_unique<RefreshRateStats>(configs, mTimeStats);
}
namespace {
@@ -82,6 +86,9 @@
init(configs);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(4);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(2);
+
std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
ASSERT_EQ(2, times.size());
ASSERT_EQ(0, times["ScreenOff"]);
@@ -136,6 +143,10 @@
init(configs);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(6);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(60, _)).Times(4);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(4);
+
std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
ASSERT_EQ(3, times.size());
ASSERT_EQ(0, times["ScreenOff"]);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index b9b0cf8..e639b4d 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -23,6 +23,7 @@
#include "ColorLayer.h"
#include "ContainerLayer.h"
#include "DisplayDevice.h"
+#include "FakePhaseOffsets.h"
#include "Layer.h"
#include "NativeWindowSurface.h"
#include "StartPropertySetThread.h"
@@ -75,6 +76,10 @@
return std::make_unique<android::impl::MessageQueue>();
}
+ std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override {
+ return std::make_unique<scheduler::FakePhaseOffsets>();
+ }
+
std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>) override {
// TODO: Use test-fixture controlled factory
return nullptr;
@@ -139,9 +144,9 @@
return nullptr;
}
- std::unique_ptr<TimeStats> createTimeStats() override {
+ std::shared_ptr<TimeStats> createTimeStats() override {
// TODO: Use test-fixture controlled factory
- return std::make_unique<TimeStats>();
+ return std::make_shared<android::impl::TimeStats>();
}
using CreateBufferQueueFunction =
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 0f95cf9..f35758d 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <log/log.h>
@@ -24,6 +25,7 @@
#include <utils/Vector.h>
#include <random>
+#include <unordered_set>
#include "TimeStats/TimeStats.h"
@@ -35,6 +37,10 @@
namespace android {
namespace {
+using testing::Contains;
+using testing::SizeIs;
+using testing::UnorderedElementsAre;
+
// clang-format off
#define FMT_PROTO true
#define FMT_STRING false
@@ -127,7 +133,7 @@
}
std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
- std::unique_ptr<TimeStats> mTimeStats = std::make_unique<TimeStats>();
+ std::unique_ptr<TimeStats> mTimeStats = std::make_unique<impl::TimeStats>();
};
std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
@@ -371,6 +377,63 @@
}
}
+TEST_F(TimeStatsTest, recordRefreshRateNewConfigs) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ uint32_t fpsOne = 30;
+ uint32_t fpsTwo = 90;
+ uint64_t millisOne = 5000;
+ uint64_t millisTwo = 7000;
+
+ mTimeStats->recordRefreshRate(fpsOne, ms2ns(millisOne));
+ mTimeStats->recordRefreshRate(fpsTwo, ms2ns(millisTwo));
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+ SFTimeStatsDisplayConfigBucketProto expectedBucketOne;
+ SFTimeStatsDisplayConfigProto* expectedConfigOne = expectedBucketOne.mutable_config();
+ expectedConfigOne->set_fps(fpsOne);
+ expectedBucketOne.set_duration_millis(millisOne);
+
+ SFTimeStatsDisplayConfigBucketProto expectedBucketTwo;
+ SFTimeStatsDisplayConfigProto* expectedConfigTwo = expectedBucketTwo.mutable_config();
+ expectedConfigTwo->set_fps(fpsTwo);
+ expectedBucketTwo.set_duration_millis(millisTwo);
+
+ EXPECT_THAT(globalProto.display_config_stats(), SizeIs(2));
+
+ std::unordered_set<uint32_t> seen_fps;
+ for (const auto& bucket : globalProto.display_config_stats()) {
+ seen_fps.emplace(bucket.config().fps());
+ if (fpsOne == bucket.config().fps()) {
+ EXPECT_EQ(millisOne, bucket.duration_millis());
+ } else if (fpsTwo == bucket.config().fps()) {
+ EXPECT_EQ(millisTwo, bucket.duration_millis());
+ } else {
+ FAIL() << "Unknown fps: " << bucket.config().fps();
+ }
+ }
+ EXPECT_THAT(seen_fps, UnorderedElementsAre(fpsOne, fpsTwo));
+}
+
+TEST_F(TimeStatsTest, recordRefreshRateUpdatesConfig) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ uint32_t fps = 30;
+ uint64_t millisOne = 5000;
+ uint64_t millisTwo = 7000;
+
+ mTimeStats->recordRefreshRate(fps, ms2ns(millisOne));
+ mTimeStats->recordRefreshRate(fps, ms2ns(millisTwo));
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+ EXPECT_THAT(globalProto.display_config_stats(), SizeIs(1));
+ EXPECT_EQ(fps, globalProto.display_config_stats().Get(0).config().fps());
+ EXPECT_EQ(millisOne + millisTwo, globalProto.display_config_stats().Get(0).duration_millis());
+}
+
TEST_F(TimeStatsTest, canRemoveTimeRecord) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
@@ -394,7 +457,7 @@
uint64_t frameNumber = 1;
nsecs_t ts = 1000000;
insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 1, 1000000);
- for (size_t i = 0; i < TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
+ for (size_t i = 0; i < impl::TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
frameNumber++;
ts += 1000000;
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, frameNumber, ts);
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.cpp b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.cpp
new file mode 100644
index 0000000..d686939
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mock/MockTimeStats.h"
+
+namespace android {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+TimeStats::TimeStats() = default;
+TimeStats::~TimeStats() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
new file mode 100644
index 0000000..08fdb9d
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 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 <gmock/gmock.h>
+
+#include "TimeStats/TimeStats.h"
+
+namespace android {
+namespace mock {
+
+class TimeStats : public android::TimeStats {
+public:
+ TimeStats();
+ ~TimeStats() override;
+
+ MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&));
+ MOCK_METHOD0(isEnabled, bool());
+ MOCK_METHOD0(incrementTotalFrames, void());
+ MOCK_METHOD0(incrementMissedFrames, void());
+ MOCK_METHOD0(incrementClientCompositionFrames, void());
+ MOCK_METHOD4(setPostTime, void(int32_t, uint64_t, const std::string&, nsecs_t));
+ 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<FenceTime>&));
+ MOCK_METHOD3(setPresentTime, void(int32_t, uint64_t, nsecs_t));
+ MOCK_METHOD3(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
+ MOCK_METHOD1(onDestroy, void(int32_t));
+ MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t));
+ MOCK_METHOD1(setPowerMode, void(int32_t));
+ MOCK_METHOD2(recordRefreshRate, void(uint32_t, nsecs_t));
+ MOCK_METHOD1(setPresentFenceGlobal, void(const std::shared_ptr<FenceTime>&));
+};
+
+} // namespace mock
+} // namespace android