Merge "vkjson: correctly handle std::numeric_limits<float>::infinity()"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 1416629..fe55fe7 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1989,12 +1989,12 @@
}
if (ds.options_->do_fb) {
- ds.screenshot_path_ = ds.GetPath(".png");
+ ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
}
ds.tmp_path_ = ds.GetPath(".tmp");
ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
- std::string destination = ds.options_->bugreport_fd.get() != -1
+ std::string destination = ds.CalledByApi()
? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
: ds.bugreport_internal_dir_.c_str();
MYLOGD(
@@ -2008,7 +2008,7 @@
ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
if (ds.options_->do_zip_file) {
- ds.path_ = ds.GetPath(".zip");
+ ds.path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
create_parent_dirs(ds.path_.c_str());
ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
@@ -2043,7 +2043,7 @@
MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
ds.name_ = name;
if (!ds.screenshot_path_.empty()) {
- std::string new_screenshot_path = ds.GetPath(".png");
+ std::string new_screenshot_path = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
new_screenshot_path.c_str(), strerror(errno));
@@ -2061,7 +2061,7 @@
} else {
do_text_file = false;
// If the user has changed the suffix, we need to change the zip file name.
- std::string new_path = ds.GetPath(".zip");
+ std::string new_path = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
if (ds.path_ != new_path) {
MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
if (rename(ds.path_.c_str(), new_path.c_str())) {
@@ -2608,7 +2608,7 @@
// Dump state for the default case. This also drops root.
RunStatus s = DumpstateDefault();
if (s != RunStatus::OK) {
- if (s == RunStatus::USER_CONSENT_TIMED_OUT) {
+ if (s == RunStatus::USER_CONSENT_DENIED) {
HandleUserConsentDenied();
}
return s;
@@ -2716,6 +2716,10 @@
ds.consent_callback_->getResult() == UserConsentResult::DENIED;
}
+bool Dumpstate::CalledByApi() const {
+ return ds.options_->bugreport_fd.get() != -1 ? true : false;
+}
+
void Dumpstate::CleanupFiles() {
android::os::UnlinkAndLogOnError(tmp_path_);
android::os::UnlinkAndLogOnError(screenshot_path_);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index ae6a721..fe330df 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -341,6 +341,11 @@
bool IsUserConsentDenied() const;
/*
+ * Returns true if dumpstate is called by bugreporting API
+ */
+ bool CalledByApi() const;
+
+ /*
* Structure to hold options that determine the behavior of dumpstate.
*/
struct DumpOptions {
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 5bde7db..f7acaf1 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -14,20 +14,21 @@
* limitations under the License.
*/
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <fcntl.h>
-#include <libgen.h>
-
#include <android-base/file.h>
#include <android/os/BnDumpstate.h>
#include <android/os/BnDumpstateListener.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <cutils/properties.h>
+#include <fcntl.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <libgen.h>
#include <ziparchive/zip_archive.h>
+#include <fstream>
+#include <regex>
+
#include "dumpstate.h"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
@@ -44,6 +45,11 @@
namespace {
+struct SectionInfo {
+ std::string name;
+ int32_t size_bytes;
+};
+
sp<IDumpstate> GetDumpstateService() {
return android::interface_cast<IDumpstate>(
android::defaultServiceManager()->getService(String16("dumpstate")));
@@ -55,14 +61,79 @@
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
}
-} // namespace
+void GetEntry(const ZipArchiveHandle archive, const std::string_view entry_name, ZipEntry* data) {
+ int32_t e = FindEntry(archive, entry_name, data);
+ EXPECT_EQ(e, 0) << ErrorCodeString(e) << " entry name: " << entry_name;
+}
-struct SectionInfo {
- std::string name;
- status_t status;
- int32_t size_bytes;
- int32_t duration_ms;
-};
+// Extracts the main bugreport txt from the given archive and writes into output_fd.
+void ExtractBugreport(const ZipArchiveHandle* handle, int output_fd) {
+ // Read contents of main_entry.txt which is a single line indicating the name of the zip entry
+ // that contains the main bugreport txt.
+ ZipEntry main_entry;
+ GetEntry(*handle, "main_entry.txt", &main_entry);
+ std::string bugreport_txt_name;
+ bugreport_txt_name.resize(main_entry.uncompressed_length);
+ ExtractToMemory(*handle, &main_entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()),
+ main_entry.uncompressed_length);
+
+ // Read the main bugreport txt and extract to output_fd.
+ ZipEntry entry;
+ GetEntry(*handle, bugreport_txt_name, &entry);
+ ExtractEntryToFile(*handle, &entry, output_fd);
+}
+
+bool IsSectionStart(const std::string& line, std::string* section_name) {
+ static const std::regex kSectionStart = std::regex{"DUMP OF SERVICE (.*):"};
+ std::smatch match;
+ if (std::regex_match(line, match, kSectionStart)) {
+ *section_name = match.str(1);
+ return true;
+ }
+ return false;
+}
+
+bool IsSectionEnd(const std::string& line) {
+ // Not all lines that contain "was the duration of" is a section end, but all section ends do
+ // contain "was the duration of". The disambiguation can be done by the caller.
+ return (line.find("was the duration of") != std::string::npos);
+}
+
+// Extracts the zipped bugreport and identifies the sections.
+void ParseSections(const std::string& zip_path, std::vector<SectionInfo>* sections) {
+ // Open the archive
+ ZipArchiveHandle handle;
+ ASSERT_EQ(OpenArchive(zip_path.c_str(), &handle), 0);
+
+ // Extract the main entry to a temp file
+ TemporaryFile tmp_binary;
+ ASSERT_NE(-1, tmp_binary.fd);
+ ExtractBugreport(&handle, tmp_binary.fd);
+
+ // Read line by line and identify sections
+ std::ifstream ifs(tmp_binary.path, std::ifstream::in);
+ std::string line;
+ int section_bytes = 0;
+ std::string current_section_name;
+ while (std::getline(ifs, line)) {
+ std::string section_name;
+ if (IsSectionStart(line, §ion_name)) {
+ section_bytes = 0;
+ current_section_name = section_name;
+ } else if (IsSectionEnd(line)) {
+ if (!current_section_name.empty()) {
+ sections->push_back({current_section_name, section_bytes});
+ }
+ current_section_name = "";
+ } else if (!current_section_name.empty()) {
+ section_bytes += line.length();
+ }
+ }
+
+ CloseArchive(handle);
+}
+
+} // namespace
/**
* Listens to bugreport progress and updates the user by writing the progress to STDOUT. All the
@@ -107,11 +178,11 @@
return binder::Status::ok();
}
- binder::Status onSectionComplete(const ::std::string& name, int32_t status, int32_t size_bytes,
- int32_t duration_ms) override {
+ binder::Status onSectionComplete(const ::std::string& name, int32_t, int32_t size_bytes,
+ int32_t) override {
std::lock_guard<std::mutex> lock(lock_);
if (sections_.get() != nullptr) {
- sections_->push_back({name, status, size_bytes, duration_ms});
+ sections_->push_back({name, size_bytes});
}
return binder::Status::ok();
}
@@ -208,29 +279,30 @@
void FileExists(const char* filename, uint32_t minsize, uint32_t maxsize) {
ZipEntry entry;
- EXPECT_EQ(FindEntry(handle, filename, &entry), 0);
+ GetEntry(handle, filename, &entry);
EXPECT_GT(entry.uncompressed_length, minsize);
EXPECT_LT(entry.uncompressed_length, maxsize);
}
};
TEST_F(ZippedBugReportContentsTest, ContainsMainEntry) {
- ZipEntry mainEntryLoc;
+ ZipEntry main_entry;
// contains main entry name file
- EXPECT_EQ(FindEntry(handle, "main_entry.txt", &mainEntryLoc), 0);
+ GetEntry(handle, "main_entry.txt", &main_entry);
- char* buf = new char[mainEntryLoc.uncompressed_length];
- ExtractToMemory(handle, &mainEntryLoc, (uint8_t*)buf, mainEntryLoc.uncompressed_length);
- delete[] buf;
+ std::string bugreport_txt_name;
+ bugreport_txt_name.resize(main_entry.uncompressed_length);
+ ExtractToMemory(handle, &main_entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()),
+ main_entry.uncompressed_length);
// contains main entry file
- FileExists(buf, 1000000U, 50000000U);
+ FileExists(bugreport_txt_name.c_str(), 1000000U, 50000000U);
}
TEST_F(ZippedBugReportContentsTest, ContainsVersion) {
ZipEntry entry;
// contains main entry name file
- EXPECT_EQ(FindEntry(handle, "version.txt", &entry), 0);
+ GetEntry(handle, "version.txt", &entry);
char* buf = new char[entry.uncompressed_length + 1];
ExtractToMemory(handle, &entry, (uint8_t*)buf, entry.uncompressed_length);
@@ -244,6 +316,10 @@
FileExists("dumpstate_board.txt", 100000U, 1000000U);
}
+TEST_F(ZippedBugReportContentsTest, ContainsProtoFile) {
+ FileExists("proto/activity.proto", 100000U, 1000000U);
+}
+
// Spot check on some files pulled from the file system
TEST_F(ZippedBugReportContentsTest, ContainsSomeFileSystemFiles) {
// FS/proc/*/mountinfo size > 0
@@ -258,6 +334,11 @@
*/
class BugreportSectionTest : public Test {
public:
+ static void SetUpTestCase() {
+ ParseSections(ZippedBugreportGenerationTest::getZipFilePath(),
+ ZippedBugreportGenerationTest::sections.get());
+ }
+
int numMatches(const std::string& substring) {
int matches = 0;
for (auto const& section : *ZippedBugreportGenerationTest::sections) {
@@ -267,10 +348,11 @@
}
return matches;
}
+
void SectionExists(const std::string& sectionName, int minsize) {
for (auto const& section : *ZippedBugreportGenerationTest::sections) {
if (sectionName == section.name) {
- EXPECT_GE(section.size_bytes, minsize);
+ EXPECT_GE(section.size_bytes, minsize) << " for section:" << sectionName;
return;
}
}
@@ -278,71 +360,59 @@
}
};
-// Test all sections are generated without timeouts or errors
-TEST_F(BugreportSectionTest, GeneratedWithoutErrors) {
- for (auto const& section : *ZippedBugreportGenerationTest::sections) {
- EXPECT_EQ(section.status, 0) << section.name << " failed with status " << section.status;
- }
-}
-
TEST_F(BugreportSectionTest, Atleast3CriticalDumpsysSectionsGenerated) {
- int numSections = numMatches("DUMPSYS CRITICAL");
+ int numSections = numMatches("CRITICAL");
EXPECT_GE(numSections, 3);
}
TEST_F(BugreportSectionTest, Atleast2HighDumpsysSectionsGenerated) {
- int numSections = numMatches("DUMPSYS HIGH");
+ int numSections = numMatches("HIGH");
EXPECT_GE(numSections, 2);
}
TEST_F(BugreportSectionTest, Atleast50NormalDumpsysSectionsGenerated) {
- int allSections = numMatches("DUMPSYS");
- int criticalSections = numMatches("DUMPSYS CRITICAL");
- int highSections = numMatches("DUMPSYS HIGH");
+ int allSections = ZippedBugreportGenerationTest::sections->size();
+ int criticalSections = numMatches("CRITICAL");
+ int highSections = numMatches("HIGH");
int normalSections = allSections - criticalSections - highSections;
EXPECT_GE(normalSections, 50) << "Total sections less than 50 (Critical:" << criticalSections
<< "High:" << highSections << "Normal:" << normalSections << ")";
}
-TEST_F(BugreportSectionTest, Atleast1ProtoDumpsysSectionGenerated) {
- int numSections = numMatches("proto/");
- EXPECT_GE(numSections, 1);
-}
-
// Test if some critical sections are being generated.
TEST_F(BugreportSectionTest, CriticalSurfaceFlingerSectionGenerated) {
- SectionExists("DUMPSYS CRITICAL - SurfaceFlinger", /* bytes= */ 10000);
+ SectionExists("CRITICAL SurfaceFlinger", /* bytes= */ 10000);
}
TEST_F(BugreportSectionTest, ActivitySectionsGenerated) {
- SectionExists("DUMPSYS CRITICAL - activity", /* bytes= */ 5000);
- SectionExists("DUMPSYS - activity", /* bytes= */ 10000);
+ SectionExists("CRITICAL activity", /* bytes= */ 5000);
+ SectionExists("activity", /* bytes= */ 10000);
}
TEST_F(BugreportSectionTest, CpuinfoSectionGenerated) {
- SectionExists("DUMPSYS CRITICAL - cpuinfo", /* bytes= */ 1000);
+ SectionExists("CRITICAL cpuinfo", /* bytes= */ 1000);
}
TEST_F(BugreportSectionTest, WindowSectionGenerated) {
- SectionExists("DUMPSYS CRITICAL - window", /* bytes= */ 20000);
+ SectionExists("CRITICAL window", /* bytes= */ 20000);
}
TEST_F(BugreportSectionTest, ConnectivitySectionsGenerated) {
- SectionExists("DUMPSYS HIGH - connectivity", /* bytes= */ 5000);
- SectionExists("DUMPSYS - connectivity", /* bytes= */ 5000);
+ SectionExists("HIGH connectivity", /* bytes= */ 3000);
+ SectionExists("connectivity", /* bytes= */ 5000);
}
TEST_F(BugreportSectionTest, MeminfoSectionGenerated) {
- SectionExists("DUMPSYS HIGH - meminfo", /* bytes= */ 100000);
+ SectionExists("HIGH meminfo", /* bytes= */ 100000);
}
TEST_F(BugreportSectionTest, BatteryStatsSectionGenerated) {
- SectionExists("DUMPSYS - batterystats", /* bytes= */ 1000);
+ SectionExists("batterystats", /* bytes= */ 1000);
}
TEST_F(BugreportSectionTest, WifiSectionGenerated) {
- SectionExists("DUMPSYS - wifi", /* bytes= */ 100000);
+ SectionExists("wifi", /* bytes= */ 100000);
}
class DumpstateBinderTest : public Test {
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index a738527..792ff91 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -1,5 +1,6 @@
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
+package android.surfaceflinger;
message Trace {
repeated Increment increment = 1;
diff --git a/cmds/surfacereplayer/replayer/Event.cpp b/cmds/surfacereplayer/replayer/Event.cpp
index 390d398..64db5f0 100644
--- a/cmds/surfacereplayer/replayer/Event.cpp
+++ b/cmds/surfacereplayer/replayer/Event.cpp
@@ -17,6 +17,7 @@
#include "Event.h"
using namespace android;
+using Increment = surfaceflinger::Increment;
Event::Event(Increment::IncrementCase type) : mIncrementType(type) {}
diff --git a/cmds/surfacereplayer/replayer/Event.h b/cmds/surfacereplayer/replayer/Event.h
index 44b60f5..09a7c24 100644
--- a/cmds/surfacereplayer/replayer/Event.h
+++ b/cmds/surfacereplayer/replayer/Event.h
@@ -24,6 +24,8 @@
namespace android {
+using Increment = surfaceflinger::Increment;
+
class Event {
public:
Event(Increment::IncrementCase);
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index d7709cc..3b94618 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -38,6 +38,8 @@
#include <unordered_map>
#include <utility>
+using namespace android::surfaceflinger;
+
namespace android {
const auto DEFAULT_PATH = "/data/local/tmp/SurfaceTrace.dat";
diff --git a/data/etc/android.hardware.se.omapi.ese.xml b/data/etc/android.hardware.se.omapi.ese.xml
new file mode 100644
index 0000000..3b1d81c
--- /dev/null
+++ b/data/etc/android.hardware.se.omapi.ese.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<!-- This feature indicates that the device supports The device supports
+ Open Mobile API capable ESE-based secure elements-->
+<permissions>
+ <feature name="android.hardware.se.omapi.ese" />
+</permissions>
diff --git a/data/etc/android.hardware.se.omapi.sd.xml b/data/etc/android.hardware.se.omapi.sd.xml
new file mode 100644
index 0000000..8fc2869
--- /dev/null
+++ b/data/etc/android.hardware.se.omapi.sd.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<!-- This feature indicates that the device supports The device supports
+ Open Mobile API capable SD-based secure elements-->
+<permissions>
+ <feature name="android.hardware.se.omapi.sd" />
+</permissions>
diff --git a/data/etc/android.hardware.se.omapi.uicc.xml b/data/etc/android.hardware.se.omapi.uicc.xml
new file mode 100644
index 0000000..9c6f143
--- /dev/null
+++ b/data/etc/android.hardware.se.omapi.uicc.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<!-- This feature indicates that the device supports The device supports
+ Open Mobile API capable UICC-based secure elements-->
+<permissions>
+ <feature name="android.hardware.se.omapi.uicc" />
+</permissions>
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 44883cc..1b589bc 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -83,7 +83,7 @@
* Power a callback to be run on the next frame. The data pointer provided will
* be passed to the callback function when it's called.
*/
-void AChoreographer_postFrameCallback64(AChoreographer* chroreographer,
+void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
AChoreographer_frameCallback64 callback, void* data) __INTRODUCED_IN(29);
/**
diff --git a/include/input/Input.h b/include/input/Input.h
index ad8c233..cbd1a41 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -469,14 +469,16 @@
inline float getYPrecision() const { return mYPrecision; }
- inline float getRawXCursorPosition() const { return mXCursorPosition; }
+ inline float getRawXCursorPosition() const { return mRawXCursorPosition; }
float getXCursorPosition() const;
- inline float getRawYCursorPosition() const { return mYCursorPosition; }
+ inline float getRawYCursorPosition() const { return mRawYCursorPosition; }
float getYCursorPosition() const;
+ void setCursorPosition(float x, float y);
+
static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); }
inline nsecs_t getDownTime() const { return mDownTime; }
@@ -623,8 +625,8 @@
void initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action,
int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState,
int32_t buttonState, MotionClassification classification, float xOffset,
- float yOffset, float xPrecision, float yPrecision, float mXCursorPosition,
- float mYCursorPosition, nsecs_t downTime, nsecs_t eventTime,
+ float yOffset, float xPrecision, float yPrecision, float rawXCursorPosition,
+ float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime,
size_t pointerCount, const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords);
@@ -676,8 +678,8 @@
float mYOffset;
float mXPrecision;
float mYPrecision;
- float mXCursorPosition;
- float mYCursorPosition;
+ float mRawXCursorPosition;
+ float mRawYCursorPosition;
nsecs_t mDownTime;
Vector<PointerProperties> mPointerProperties;
Vector<nsecs_t> mSampleEventTimes;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index b5fbf42..6bd97d58 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -102,10 +102,6 @@
reinterpret_cast<IBinder*>(obj.cookie)->incStrong(who);
}
return;
- case BINDER_TYPE_WEAK_BINDER:
- if (obj.binder)
- reinterpret_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who);
- return;
case BINDER_TYPE_HANDLE: {
const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
if (b != nullptr) {
@@ -114,11 +110,6 @@
}
return;
}
- case BINDER_TYPE_WEAK_HANDLE: {
- const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
- if (b != nullptr) b.get_refs()->incWeak(who);
- return;
- }
case BINDER_TYPE_FD: {
if ((obj.cookie != 0) && (outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
// If we own an ashmem fd, keep track of how much memory it refers to.
@@ -144,10 +135,6 @@
reinterpret_cast<IBinder*>(obj.cookie)->decStrong(who);
}
return;
- case BINDER_TYPE_WEAK_BINDER:
- if (obj.binder)
- reinterpret_cast<RefBase::weakref_type*>(obj.binder)->decWeak(who);
- return;
case BINDER_TYPE_HANDLE: {
const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
if (b != nullptr) {
@@ -156,11 +143,6 @@
}
return;
}
- case BINDER_TYPE_WEAK_HANDLE: {
- const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
- if (b != nullptr) b.get_refs()->decWeak(who);
- return;
- }
case BINDER_TYPE_FD: {
if (obj.cookie != 0) { // owned
if ((outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
@@ -230,55 +212,6 @@
return finish_flatten_binder(binder, obj, out);
}
-static status_t flatten_binder(const sp<ProcessState>& /*proc*/,
- const wp<IBinder>& binder, Parcel* out)
-{
- flat_binder_object obj;
-
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- if (binder != nullptr) {
- sp<IBinder> real = binder.promote();
- if (real != nullptr) {
- IBinder *local = real->localBinder();
- if (!local) {
- BpBinder *proxy = real->remoteBinder();
- if (proxy == nullptr) {
- ALOGE("null proxy");
- }
- const int32_t handle = proxy ? proxy->handle() : 0;
- obj.hdr.type = BINDER_TYPE_WEAK_HANDLE;
- obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
- obj.handle = handle;
- obj.cookie = 0;
- } else {
- obj.hdr.type = BINDER_TYPE_WEAK_BINDER;
- obj.binder = reinterpret_cast<uintptr_t>(binder.get_refs());
- obj.cookie = reinterpret_cast<uintptr_t>(binder.unsafe_get());
- }
- return finish_flatten_binder(real, obj, out);
- }
-
- // XXX How to deal? In order to flatten the given binder,
- // we need to probe it for information, which requires a primary
- // reference... but we don't have one.
- //
- // The OpenBinder implementation uses a dynamic_cast<> here,
- // but we can't do that with the different reference counting
- // implementation we are using.
- ALOGE("Unable to unflatten Binder weak reference!");
- obj.hdr.type = BINDER_TYPE_BINDER;
- obj.binder = 0;
- obj.cookie = 0;
- return finish_flatten_binder(nullptr, obj, out);
-
- } else {
- obj.hdr.type = BINDER_TYPE_BINDER;
- obj.binder = 0;
- obj.cookie = 0;
- return finish_flatten_binder(nullptr, obj, out);
- }
-}
-
inline static status_t finish_unflatten_binder(
BpBinder* /*proxy*/, const flat_binder_object& /*flat*/,
const Parcel& /*in*/)
@@ -305,35 +238,6 @@
return BAD_TYPE;
}
-static status_t unflatten_binder(const sp<ProcessState>& proc,
- const Parcel& in, wp<IBinder>* out)
-{
- const flat_binder_object* flat = in.readObject(false);
-
- if (flat) {
- switch (flat->hdr.type) {
- case BINDER_TYPE_BINDER:
- *out = reinterpret_cast<IBinder*>(flat->cookie);
- return finish_unflatten_binder(nullptr, *flat, in);
- case BINDER_TYPE_WEAK_BINDER:
- if (flat->binder != 0) {
- out->set_object_and_refs(
- reinterpret_cast<IBinder*>(flat->cookie),
- reinterpret_cast<RefBase::weakref_type*>(flat->binder));
- } else {
- *out = nullptr;
- }
- return finish_unflatten_binder(nullptr, *flat, in);
- case BINDER_TYPE_HANDLE:
- case BINDER_TYPE_WEAK_HANDLE:
- *out = proc->getWeakProxyForHandle(flat->handle);
- return finish_unflatten_binder(
- static_cast<BpBinder*>(out->unsafe_get()), *flat, in);
- }
- }
- return BAD_TYPE;
-}
-
// ---------------------------------------------------------------------------
Parcel::Parcel()
@@ -590,6 +494,12 @@
}
}
+#ifdef __ANDROID_VNDK__
+constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
+#else
+constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
+#endif
+
// Write RPC headers. (previously just the interface token)
status_t Parcel::writeInterfaceToken(const String16& interface)
{
@@ -598,6 +508,7 @@
updateWorkSourceRequestHeaderPosition();
writeInt32(threadState->shouldPropagateWorkSource() ?
threadState->getCallingWorkSourceUid() : IPCThreadState::kUnsetWorkSource);
+ writeInt32(kHeader);
// currently the interface identification token is just its name as a string
return writeString16(interface);
}
@@ -655,6 +566,12 @@
updateWorkSourceRequestHeaderPosition();
int32_t workSource = readInt32();
threadState->setCallingWorkSourceUidWithoutPropagation(workSource);
+ // vendor header
+ int32_t header = readInt32();
+ if (header != kHeader) {
+ ALOGE("Expecting header 0x%x but found 0x%x. Mixing copies of libbinder?", kHeader, header);
+ return false;
+ }
// Interface descriptor.
const String16 str(readString16());
if (str == interface) {
@@ -1136,11 +1053,6 @@
return readTypedVector(val, &Parcel::readStrongBinder);
}
-status_t Parcel::writeWeakBinder(const wp<IBinder>& val)
-{
- return flatten_binder(ProcessState::self(), val, this);
-}
-
status_t Parcel::writeRawNullableParcelable(const Parcelable* parcelable) {
if (!parcelable) {
return writeInt32(0);
@@ -2079,13 +1991,6 @@
return val;
}
-wp<IBinder> Parcel::readWeakBinder() const
-{
- wp<IBinder> val;
- unflatten_binder(ProcessState::self(), *this, &val);
- return val;
-}
-
status_t Parcel::readParcelable(Parcelable* parcelable) const {
int32_t have_parcelable = 0;
status_t status = readInt32(&have_parcelable);
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index a07b3a0..1e1bc3a 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -210,8 +210,12 @@
if (e != nullptr) {
// We need to create a new BpBinder if there isn't currently one, OR we
- // are unable to acquire a weak reference on this current one. See comment
- // in getWeakProxyForHandle() for more info about this.
+ // are unable to acquire a weak reference on this current one. The
+ // attemptIncWeak() is safe because we know the BpBinder destructor will always
+ // call expungeHandle(), which acquires the same lock we are holding now.
+ // We need to do this because there is a race condition between someone
+ // releasing a reference on this BpBinder, and a new reference on its handle
+ // arriving from the driver.
IBinder* b = e->binder;
if (b == nullptr || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
@@ -257,37 +261,6 @@
return result;
}
-wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle)
-{
- wp<IBinder> result;
-
- AutoMutex _l(mLock);
-
- handle_entry* e = lookupHandleLocked(handle);
-
- if (e != nullptr) {
- // We need to create a new BpBinder if there isn't currently one, OR we
- // are unable to acquire a weak reference on this current one. The
- // attemptIncWeak() is safe because we know the BpBinder destructor will always
- // call expungeHandle(), which acquires the same lock we are holding now.
- // We need to do this because there is a race condition between someone
- // releasing a reference on this BpBinder, and a new reference on its handle
- // arriving from the driver.
- IBinder* b = e->binder;
- if (b == nullptr || !e->refs->attemptIncWeak(this)) {
- b = BpBinder::create(handle);
- result = b;
- e->binder = b;
- if (b) e->refs = b->getWeakRefs();
- } else {
- result = b;
- e->refs->decWeak(this);
- }
- }
-
- return result;
-}
-
void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
{
AutoMutex _l(mLock);
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index b65d456..28ab4d9 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -117,7 +117,6 @@
status_t writeString16(const std::unique_ptr<String16>& str);
status_t writeString16(const char16_t* str, size_t len);
status_t writeStrongBinder(const sp<IBinder>& val);
- status_t writeWeakBinder(const wp<IBinder>& val);
status_t writeInt32Array(size_t len, const int32_t *val);
status_t writeByteArray(size_t len, const uint8_t *val);
status_t writeBool(bool val);
@@ -273,7 +272,6 @@
sp<IBinder> readStrongBinder() const;
status_t readStrongBinder(sp<IBinder>* val) const;
status_t readNullableStrongBinder(sp<IBinder>* val) const;
- wp<IBinder> readWeakBinder() const;
template<typename T>
status_t readParcelableVector(
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 3af9eed..8339976 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -58,7 +58,6 @@
void* userData);
sp<IBinder> getStrongProxyForHandle(int32_t handle);
- wp<IBinder> getWeakProxyForHandle(int32_t handle);
void expungeHandle(int32_t handle, IBinder* binder);
void spawnPooledThread(bool isMain);
diff --git a/libs/binder/ndk/include_apex/android/binder_process.h b/libs/binder/ndk/include_apex/android/binder_process.h
index 69e6387..fdefbb4 100644
--- a/libs/binder/ndk/include_apex/android/binder_process.h
+++ b/libs/binder/ndk/include_apex/android/binder_process.h
@@ -27,7 +27,7 @@
void ABinderProcess_startThreadPool();
/**
* This sets the maximum number of threads that can be started in the threadpool. By default, after
- * startThreadPool is called, this is one. If it is called additional times, it will only prevent
+ * startThreadPool is called, this is 15. If it is called additional times, it will only prevent
* the kernel from starting new threads and will not delete already existing threads.
*/
bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads);
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index e51bceb..9de3460 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -66,7 +66,6 @@
BINDER_LIB_TEST_LINK_DEATH_TRANSACTION,
BINDER_LIB_TEST_WRITE_FILE_TRANSACTION,
BINDER_LIB_TEST_WRITE_PARCEL_FILE_DESCRIPTOR_TRANSACTION,
- BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION,
BINDER_LIB_TEST_EXIT_TRANSACTION,
BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION,
BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION,
@@ -770,22 +769,6 @@
EXPECT_TRUE(strong_from_weak == nullptr);
}
-TEST_F(BinderLibTest, PromoteRemote) {
- int ret;
- Parcel data, reply;
- sp<IBinder> strong = new BBinder();
- sp<IBinder> server = addServer();
-
- ASSERT_TRUE(server != nullptr);
- ASSERT_TRUE(strong != nullptr);
-
- ret = data.writeWeakBinder(strong);
- EXPECT_EQ(NO_ERROR, ret);
-
- ret = server->transact(BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION, data, &reply);
- EXPECT_GE(ret, 0);
-}
-
TEST_F(BinderLibTest, CheckHandleZeroBinderHighBitsZeroCookie) {
status_t ret;
Parcel data, reply;
@@ -811,7 +794,6 @@
wp<IBinder> keepFreedBinder;
{
Parcel data, reply;
- data.writeBool(false); /* request weak reference */
ret = server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, data, &reply);
ASSERT_EQ(NO_ERROR, ret);
struct flat_binder_object *freed = (struct flat_binder_object *)(reply.data());
@@ -820,8 +802,9 @@
* delete its reference to it - otherwise the transaction
* fails regardless of whether the driver is fixed.
*/
- keepFreedBinder = reply.readWeakBinder();
+ keepFreedBinder = reply.readStrongBinder();
}
+ IPCThreadState::self()->flushCommands();
{
Parcel data, reply;
data.writeStrongBinder(server);
@@ -1280,29 +1263,6 @@
if (ret != size) return UNKNOWN_ERROR;
return NO_ERROR;
}
- case BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION: {
- int ret;
- wp<IBinder> weak;
- sp<IBinder> strong;
- Parcel data2, reply2;
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> server = sm->getService(binderLibTestServiceName);
-
- weak = data.readWeakBinder();
- if (weak == nullptr) {
- return BAD_VALUE;
- }
- strong = weak.promote();
-
- ret = server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data2, &reply2);
- if (ret != NO_ERROR)
- exit(EXIT_FAILURE);
-
- if (strong == nullptr) {
- reply->setError(1);
- }
- return NO_ERROR;
- }
case BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION:
alarm(10);
return NO_ERROR;
@@ -1311,13 +1271,8 @@
;
exit(EXIT_SUCCESS);
case BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION: {
- bool strongRef = data.readBool();
sp<IBinder> binder = new BBinder();
- if (strongRef) {
- reply->writeStrongBinder(binder);
- } else {
- reply->writeWeakBinder(binder);
- }
+ reply->writeStrongBinder(binder);
return NO_ERROR;
}
case BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION: {
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 8199c98..59f1bcd 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -46,7 +46,6 @@
#include <utils/String8.h>
#include <utils/Trace.h>
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
#define EGL_PROTECTED_CONTENT_EXT 0x32C0
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index bf7991a..be58b85 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -169,12 +169,10 @@
}
status_t ComposerState::write(Parcel& output) const {
- output.writeStrongBinder(IInterface::asBinder(client));
return state.write(output);
}
status_t ComposerState::read(const Parcel& input) {
- client = interface_cast<ISurfaceComposerClient>(input.readStrongBinder());
return state.read(input);
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 16a4b35..e6b1beb 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -202,7 +202,8 @@
* callbackIds to generate one super map that contains all the sp<IBinder> to sp<SurfaceControl>
* that could possibly exist for the callbacks.
*/
- std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls;
+ std::unordered_map<sp<IBinder>, sp<SurfaceControl>, SurfaceComposerClient::IBinderHash>
+ surfaceControls;
for (const auto& transactionStats : listenerStats.transactionStats) {
for (auto callbackId : transactionStats.callbackIds) {
auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId];
@@ -365,16 +366,16 @@
if (count > parcel->dataSize()) {
return BAD_VALUE;
}
- std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> composerStates;
+ std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> composerStates;
composerStates.reserve(count);
for (size_t i = 0; i < count; i++) {
- sp<SurfaceControl> surfaceControl = SurfaceControl::readFromParcel(parcel);
+ sp<IBinder> surfaceControlHandle = parcel->readStrongBinder();
ComposerState composerState;
if (composerState.read(*parcel) == BAD_VALUE) {
return BAD_VALUE;
}
- composerStates[surfaceControl] = composerState;
+ composerStates[surfaceControlHandle] = composerState;
}
InputWindowCommands inputWindowCommands;
@@ -408,8 +409,8 @@
}
parcel->writeUint32(static_cast<uint32_t>(mComposerStates.size()));
- for (auto const& [surfaceControl, composerState] : mComposerStates) {
- surfaceControl->writeToParcel(parcel);
+ for (auto const& [surfaceHandle, composerState] : mComposerStates) {
+ parcel->writeStrongBinder(surfaceHandle);
composerState.write(*parcel);
}
@@ -418,11 +419,11 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
- for (auto const& kv : other.mComposerStates) {
- if (mComposerStates.count(kv.first) == 0) {
- mComposerStates[kv.first] = kv.second;
+ for (auto const& [surfaceHandle, composerState] : other.mComposerStates) {
+ if (mComposerStates.count(surfaceHandle) == 0) {
+ mComposerStates[surfaceHandle] = composerState;
} else {
- mComposerStates[kv.first].state.merge(kv.second.state);
+ mComposerStates[surfaceHandle].state.merge(composerState.state);
}
}
@@ -466,14 +467,12 @@
mDesiredPresentTime = -1;
}
-void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle,
- const sp<ISurfaceComposerClient>& client) {
+void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
Vector<ComposerState> composerStates;
Vector<DisplayState> displayStates;
ComposerState s;
- s.client = client;
s.state.surface = handle;
s.state.what |= layer_state_t::eReparent;
s.state.parentHandleForChild = nullptr;
@@ -500,8 +499,8 @@
}
size_t count = 0;
- for (auto& [sc, cs] : mComposerStates) {
- layer_state_t* s = getLayerState(sc);
+ for (auto& [handle, cs] : mComposerStates) {
+ layer_state_t* s = getLayerState(handle);
if (!(s->what & layer_state_t::eBufferChanged)) {
continue;
}
@@ -640,16 +639,15 @@
mEarlyWakeup = true;
}
-layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
- if (mComposerStates.count(sc) == 0) {
+layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<IBinder>& handle) {
+ if (mComposerStates.count(handle) == 0) {
// we don't have it, add an initialized layer_state to our list
ComposerState s;
- s.client = sc->getClient()->mClient;
- s.state.surface = sc->getHandle();
- mComposerStates[sc] = s;
+ s.state.surface = handle;
+ mComposerStates[handle] = s;
}
- return &(mComposerStates[sc].state);
+ return &(mComposerStates[handle].state);
}
void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback(
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index b9defdd..071314f 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -65,8 +65,8 @@
{
// Avoid reparenting the server-side surface to null if we are not the owner of it,
// meaning that we retrieved it from another process.
- if (mClient != nullptr && mHandle != nullptr && mOwned) {
- SurfaceComposerClient::doDropReferenceTransaction(mHandle, mClient->getClient());
+ if (mHandle != nullptr && mOwned) {
+ SurfaceComposerClient::doDropReferenceTransaction(mHandle);
}
release();
}
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index f438eb3..cbd1c85 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -206,7 +206,6 @@
};
struct ComposerState {
- sp<ISurfaceComposerClient> client;
layer_state_t state;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
@@ -274,8 +273,6 @@
};
static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
- if (lhs.client < rhs.client) return -1;
- if (lhs.client > rhs.client) return 1;
if (lhs.state.surface < rhs.state.surface) return -1;
if (lhs.state.surface > rhs.state.surface) return 1;
return 0;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 4dda97f..22ab62d 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -163,8 +163,7 @@
* Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it
* to null), but without needing an sp<SurfaceControl> to avoid infinite ressurection.
*/
- static void doDropReferenceTransaction(const sp<IBinder>& handle,
- const sp<ISurfaceComposerClient>& client);
+ static void doDropReferenceTransaction(const sp<IBinder>& handle);
/**
* Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is
@@ -270,6 +269,12 @@
}
};
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& iBinder) const {
+ return std::hash<IBinder*>{}(iBinder.get());
+ }
+ };
+
struct TCLHash {
std::size_t operator()(const sp<ITransactionCompletedListener>& tcl) const {
return std::hash<IBinder*>{}((tcl) ? IInterface::asBinder(tcl).get() : nullptr);
@@ -286,7 +291,7 @@
};
class Transaction : Parcelable {
- std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
+ std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates;
SortedVector<DisplayState > mDisplayStates;
std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
mListenerCallbacks;
@@ -314,7 +319,10 @@
InputWindowCommands mInputWindowCommands;
int mStatus = NO_ERROR;
- layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
+ layer_state_t* getLayerState(const sp<IBinder>& surfaceHandle);
+ layer_state_t* getLayerState(const sp<SurfaceControl>& sc) {
+ return getLayerState(sc->getHandle());
+ }
DisplayState& getDisplayState(const sp<IBinder>& token);
void cacheBuffers();
@@ -560,15 +568,10 @@
CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1;
- struct IBinderHash {
- std::size_t operator()(const sp<IBinder>& iBinder) const {
- return std::hash<IBinder*>{}(iBinder.get());
- }
- };
-
struct CallbackTranslation {
TransactionCompletedCallback callbackFunction;
- std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls;
+ std::unordered_map<sp<IBinder>, sp<SurfaceControl>, SurfaceComposerClient::IBinderHash>
+ surfaceControls;
};
std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 65e09f2..c85e844 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -28,8 +28,6 @@
#include <utils/Log.h>
#include <utils/Thread.h>
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-
namespace android {
class SurfaceTextureClientTest : public ::testing::Test {
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index dc4978b..34b305e 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -238,8 +238,8 @@
int32_t actionButton, int32_t flags, int32_t edgeFlags,
int32_t metaState, int32_t buttonState,
MotionClassification classification, float xOffset, float yOffset,
- float xPrecision, float yPrecision, float xCursorPosition,
- float yCursorPosition, nsecs_t downTime, nsecs_t eventTime,
+ float xPrecision, float yPrecision, float rawXCursorPosition,
+ float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime,
size_t pointerCount, const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords) {
InputEvent::initialize(deviceId, source, displayId);
@@ -254,8 +254,8 @@
mYOffset = yOffset;
mXPrecision = xPrecision;
mYPrecision = yPrecision;
- mXCursorPosition = xCursorPosition;
- mYCursorPosition = yCursorPosition;
+ mRawXCursorPosition = rawXCursorPosition;
+ mRawYCursorPosition = rawYCursorPosition;
mDownTime = downTime;
mPointerProperties.clear();
mPointerProperties.appendArray(pointerProperties, pointerCount);
@@ -277,8 +277,8 @@
mYOffset = other->mYOffset;
mXPrecision = other->mXPrecision;
mYPrecision = other->mYPrecision;
- mXCursorPosition = other->mXCursorPosition;
- mYCursorPosition = other->mYCursorPosition;
+ mRawXCursorPosition = other->mRawXCursorPosition;
+ mRawYCursorPosition = other->mRawYCursorPosition;
mDownTime = other->mDownTime;
mPointerProperties = other->mPointerProperties;
@@ -313,6 +313,11 @@
return rawY + mYOffset;
}
+void MotionEvent::setCursorPosition(float x, float y) {
+ mRawXCursorPosition = x - mXOffset;
+ mRawYCursorPosition = y - mYOffset;
+}
+
const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
}
@@ -433,12 +438,12 @@
transformPoint(matrix, 0, 0, &originX, &originY);
// Apply the transformation to cursor position.
- if (isValidCursorPosition(mXCursorPosition, mYCursorPosition)) {
- float x = mXCursorPosition + oldXOffset;
- float y = mYCursorPosition + oldYOffset;
+ if (isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) {
+ float x = mRawXCursorPosition + oldXOffset;
+ float y = mRawYCursorPosition + oldYOffset;
transformPoint(matrix, x, y, &x, &y);
- mXCursorPosition = x - mXOffset;
- mYCursorPosition = y - mYOffset;
+ mRawXCursorPosition = x - mXOffset;
+ mRawYCursorPosition = y - mYOffset;
}
// Apply the transformation to all samples.
@@ -480,8 +485,8 @@
mYOffset = parcel->readFloat();
mXPrecision = parcel->readFloat();
mYPrecision = parcel->readFloat();
- mXCursorPosition = parcel->readFloat();
- mYCursorPosition = parcel->readFloat();
+ mRawXCursorPosition = parcel->readFloat();
+ mRawYCursorPosition = parcel->readFloat();
mDownTime = parcel->readInt64();
mPointerProperties.clear();
@@ -533,8 +538,8 @@
parcel->writeFloat(mYOffset);
parcel->writeFloat(mXPrecision);
parcel->writeFloat(mYPrecision);
- parcel->writeFloat(mXCursorPosition);
- parcel->writeFloat(mYCursorPosition);
+ parcel->writeFloat(mRawXCursorPosition);
+ parcel->writeFloat(mRawYCursorPosition);
parcel->writeInt64(mDownTime);
for (size_t i = 0; i < pointerCount; i++) {
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index 5a60347..ec28757 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -99,7 +99,7 @@
applicationInfo.write(output);
output.write(touchableRegion);
output.writeBool(replaceTouchableRegionWithCrop);
- output.writeWeakBinder(touchableRegionCropHandle);
+ output.writeStrongBinder(touchableRegionCropHandle.promote());
return OK;
}
@@ -142,7 +142,7 @@
ret.applicationInfo = InputApplicationInfo::read(from);
from.read(ret.touchableRegion);
ret.replaceTouchableRegionWithCrop = from.readBool();
- ret.touchableRegionCropHandle = from.readWeakBinder();
+ ret.touchableRegionCropHandle = from.readStrongBinder();
return ret;
}
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index b879de6..b90857c 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -665,4 +665,14 @@
ASSERT_EQ(600, event.getYCursorPosition());
}
+TEST_F(MotionEventTest, SetCursorPosition) {
+ MotionEvent event;
+ initializeEventWithHistory(&event);
+ event.setSource(AINPUT_SOURCE_MOUSE);
+
+ event.setCursorPosition(3, 4);
+ ASSERT_EQ(3, event.getXCursorPosition());
+ ASSERT_EQ(4, event.getYCursorPosition());
+}
+
} // namespace android
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index 5200545..8ed09f8 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -199,6 +199,10 @@
int32_t type = data.readInt32();
int32_t format = data.readInt32();
native_handle_t *resource = data.readNativeHandle();
+ // Avoid a crash in native_handle_close if resource is nullptr
+ if (resource == nullptr) {
+ return BAD_VALUE;
+ }
sp<ISensorEventConnection> ch =
createSensorDirectConnection(opPackageName, size, type, format, resource);
native_handle_close(resource);
diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
index 3786d1d..861dc6c 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
@@ -191,7 +191,8 @@
enum class ConfigFileType : uint32_t {
kLensMetrics,
kDeviceMetrics,
- kDeviceConfiguration
+ kDeviceConfiguration,
+ kDeviceEdid
};
struct DisplayProtocol {
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index e383bb2..b7abb99 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -85,6 +85,8 @@
DVR_CONFIGURATION_DATA_DEVICE_METRICS = 1,
// Request the per device configuration data file.
DVR_CONFIGURATION_DATA_DEVICE_CONFIG = 2,
+ // Request the edid data for the display.
+ DVR_CONFIGURATION_DATA_DEVICE_EDID = 3,
};
// dvr_display_manager.h
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 87162c0..8980a92 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -44,6 +44,18 @@
Endpoint::Create(display::DisplayProtocol::kClientPath)) {
hardware_composer_.Initialize(
hidl, primary_display_id, request_display_callback);
+
+ uint8_t port;
+ const auto error = hidl->getDisplayIdentificationData(
+ primary_display_id, &port, &display_identification_data_);
+ if (error != android::hardware::graphics::composer::V2_1::Error::NONE) {
+ if (error !=
+ android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) {
+ ALOGI("DisplayService: identification data error\n");
+ } else {
+ ALOGI("DisplayService: identification data unsupported\n");
+ }
+ }
}
bool DisplayService::IsInitialized() const {
@@ -204,6 +216,12 @@
case display::ConfigFileType::kDeviceConfiguration:
property_name = kDvrDeviceConfigProperty;
break;
+ case display::ConfigFileType::kDeviceEdid:
+ if (display_identification_data_.size() == 0) {
+ return ErrorStatus(ENOENT);
+ }
+ return std::string(display_identification_data_.begin(),
+ display_identification_data_.end());
default:
return ErrorStatus(EINVAL);
}
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index e0f2edd..d45a61f 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -18,6 +18,8 @@
#include "epoll_event_dispatcher.h"
#include "hardware_composer.h"
+#include "DisplayHardware/DisplayIdentification.h"
+
namespace android {
namespace dvr {
@@ -117,6 +119,8 @@
DisplayService(const DisplayService&) = delete;
void operator=(const DisplayService&) = delete;
+
+ DisplayIdentificationData display_identification_data_;
};
} // namespace dvr
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index fb28d1b..019815c 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -715,7 +715,7 @@
CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
Command command = commandEntry->command;
- (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'
+ command(*this, commandEntry); // commands are implicitly 'LockedInterruptible'
commandEntry->connection.clear();
delete commandEntry;
@@ -809,8 +809,8 @@
resetKeyRepeatLocked();
// Enqueue a command to run outside the lock to tell the policy that the configuration changed.
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
commandEntry->eventTime = entry->eventTime;
return true;
}
@@ -884,7 +884,7 @@
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
+ &InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
if (focusedWindowHandle != nullptr) {
@@ -1982,8 +1982,8 @@
}
}
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doPokeUserActivityLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doPokeUserActivityLockedInterruptible);
commandEntry->eventTime = eventEntry->eventTime;
commandEntry->userActivityEventType = eventType;
}
@@ -2200,8 +2200,8 @@
return;
}
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
commandEntry->newToken = newToken;
}
@@ -4087,8 +4087,8 @@
void InputDispatcher::onDispatchCycleFinishedLocked(
nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
commandEntry->connection = connection;
commandEntry->eventTime = currentTime;
commandEntry->seq = seq;
@@ -4100,8 +4100,8 @@
ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
connection->getInputChannelName().c_str());
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
commandEntry->connection = connection;
}
@@ -4109,8 +4109,8 @@
const sp<InputWindowHandle>& newFocus) {
sp<IBinder> oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr;
sp<IBinder> newToken = newFocus != nullptr ? newFocus->getToken() : nullptr;
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doNotifyFocusChangedLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doNotifyFocusChangedLockedInterruptible);
commandEntry->oldToken = oldToken;
commandEntry->newToken = newToken;
}
@@ -4142,8 +4142,8 @@
mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason);
dumpDispatchStateLocked(mLastANRState);
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doNotifyANRLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doNotifyANRLockedInterruptible);
commandEntry->inputApplicationHandle = applicationHandle;
commandEntry->inputChannel = windowHandle != nullptr ?
getInputChannelLocked(windowHandle->getToken()) : nullptr;
@@ -4237,53 +4237,55 @@
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
CommandEntry* commandEntry) {
sp<Connection> connection = commandEntry->connection;
- nsecs_t finishTime = commandEntry->eventTime;
+ const nsecs_t finishTime = commandEntry->eventTime;
uint32_t seq = commandEntry->seq;
- bool handled = commandEntry->handled;
+ const bool handled = commandEntry->handled;
// Handle post-event policy actions.
DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);
- if (dispatchEntry) {
- nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
- if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
- std::string msg =
- StringPrintf("Window '%s' spent %0.1fms processing the last input event: ",
- connection->getWindowName().c_str(), eventDuration * 0.000001f);
- dispatchEntry->eventEntry->appendDescription(msg);
- ALOGI("%s", msg.c_str());
- }
-
- bool restartEvent;
- if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
- KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
- restartEvent = afterKeyEventLockedInterruptible(connection,
- dispatchEntry, keyEntry, handled);
- } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
- restartEvent = afterMotionEventLockedInterruptible(connection,
- dispatchEntry, motionEntry, handled);
- } else {
- restartEvent = false;
- }
-
- // Dequeue the event and start the next cycle.
- // Note that because the lock might have been released, it is possible that the
- // contents of the wait queue to have been drained, so we need to double-check
- // a few things.
- if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
- connection->waitQueue.dequeue(dispatchEntry);
- traceWaitQueueLength(connection);
- if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
- connection->outboundQueue.enqueueAtHead(dispatchEntry);
- traceOutboundQueueLength(connection);
- } else {
- releaseDispatchEntry(dispatchEntry);
- }
- }
-
- // Start the next dispatch cycle for this connection.
- startDispatchCycleLocked(now(), connection);
+ if (!dispatchEntry) {
+ return;
}
+
+ nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
+ if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
+ std::string msg =
+ StringPrintf("Window '%s' spent %0.1fms processing the last input event: ",
+ connection->getWindowName().c_str(), eventDuration * 0.000001f);
+ dispatchEntry->eventEntry->appendDescription(msg);
+ ALOGI("%s", msg.c_str());
+ }
+
+ bool restartEvent;
+ if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
+ KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
+ restartEvent =
+ afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled);
+ } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
+ MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
+ restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry,
+ handled);
+ } else {
+ restartEvent = false;
+ }
+
+ // Dequeue the event and start the next cycle.
+ // Note that because the lock might have been released, it is possible that the
+ // contents of the wait queue to have been drained, so we need to double-check
+ // a few things.
+ if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
+ connection->waitQueue.dequeue(dispatchEntry);
+ traceWaitQueueLength(connection);
+ if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
+ connection->outboundQueue.enqueueAtHead(dispatchEntry);
+ traceOutboundQueueLength(connection);
+ } else {
+ releaseDispatchEntry(dispatchEntry);
+ }
+ }
+
+ // Start the next dispatch cycle for this connection.
+ startDispatchCycleLocked(now(), connection);
}
bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection,
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index c30a8d6..147437c 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -644,7 +644,7 @@
//
// Commands are implicitly 'LockedInterruptible'.
struct CommandEntry;
- typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry);
+ typedef std::function<void(InputDispatcher&, CommandEntry*)> Command;
class Connection;
struct CommandEntry : Link<CommandEntry> {
diff --git a/services/nativeperms/.clang-format b/services/nativeperms/.clang-format
deleted file mode 100644
index 6006e6f..0000000
--- a/services/nativeperms/.clang-format
+++ /dev/null
@@ -1,13 +0,0 @@
-BasedOnStyle: Google
-AllowShortFunctionsOnASingleLine: Inline
-AllowShortIfStatementsOnASingleLine: true
-AllowShortLoopsOnASingleLine: true
-BinPackArguments: true
-BinPackParameters: true
-ColumnLimit: 80
-CommentPragmas: NOLINT:.*
-ContinuationIndentWidth: 8
-DerivePointerAlignment: false
-IndentWidth: 4
-PointerAlignment: Left
-TabWidth: 4
diff --git a/services/nativeperms/Android.bp b/services/nativeperms/Android.bp
deleted file mode 100644
index cbc7d66..0000000
--- a/services/nativeperms/Android.bp
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2016 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.
-//
-
-cc_binary {
- name: "nativeperms",
- srcs: [
- "nativeperms.cpp",
- "android/os/IPermissionController.aidl",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- shared_libs: [
- "libbinder",
- "libbrillo",
- "libbrillo-binder",
- "libchrome",
- "libutils",
- ],
- init_rc: ["nativeperms.rc"],
-}
diff --git a/services/nativeperms/android/os/IPermissionController.aidl b/services/nativeperms/android/os/IPermissionController.aidl
deleted file mode 100644
index 89db85c..0000000
--- a/services/nativeperms/android/os/IPermissionController.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-/* //device/java/android/android/os/IPowerManager.aidl
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.os;
-
-/** @hide */
-interface IPermissionController {
- boolean checkPermission(String permission, int pid, int uid);
- String[] getPackagesForUid(int uid);
- boolean isRuntimePermission(String permission);
-}
diff --git a/services/nativeperms/android/os/README b/services/nativeperms/android/os/README
deleted file mode 100644
index e414499..0000000
--- a/services/nativeperms/android/os/README
+++ /dev/null
@@ -1,4 +0,0 @@
-IPermissionController.aidl in this directory is a verbatim copy of
-https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/IPermissionController.aidl,
-because some Brillo manifests do not currently include the frameworks/base repo.
-TODO(jorgelo): Figure out a way to use the .aidl file in frameworks/base.
diff --git a/services/nativeperms/nativeperms.cpp b/services/nativeperms/nativeperms.cpp
deleted file mode 100644
index 7f03bed..0000000
--- a/services/nativeperms/nativeperms.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2016 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 <base/at_exit.h>
-#include <base/logging.h>
-#include <base/message_loop/message_loop.h>
-#include <binder/IServiceManager.h>
-#include <binder/Status.h>
-#include <brillo/binder_watcher.h>
-#include <brillo/message_loops/base_message_loop.h>
-#include <brillo/syslog_logging.h>
-#include <utils/String16.h>
-
-#include "android/os/BnPermissionController.h"
-
-namespace {
-static android::String16 serviceName("permission");
-}
-
-namespace android {
-
-class PermissionService : public android::os::BnPermissionController {
- public:
- ::android::binder::Status checkPermission(
- const ::android::String16& permission, int32_t pid, int32_t uid,
- bool* _aidl_return) {
- (void)permission;
- (void)pid;
- (void)uid;
- *_aidl_return = true;
- return binder::Status::ok();
- }
-
- ::android::binder::Status getPackagesForUid(
- int32_t uid, ::std::vector<::android::String16>* _aidl_return) {
- (void)uid;
- // Brillo doesn't currently have installable packages.
- if (_aidl_return) {
- _aidl_return->clear();
- }
- return binder::Status::ok();
- }
-
- ::android::binder::Status isRuntimePermission(
- const ::android::String16& permission, bool* _aidl_return) {
- (void)permission;
- // Brillo doesn't currently have runtime permissions.
- *_aidl_return = false;
- return binder::Status::ok();
- }
-};
-
-} // namespace android
-
-int main() {
- base::AtExitManager atExitManager;
- brillo::InitLog(brillo::kLogToSyslog);
- // Register the service with servicemanager.
- android::status_t status = android::defaultServiceManager()->addService(
- serviceName, new android::PermissionService());
- CHECK(status == android::OK) << "Failed to get IPermissionController "
- "binder from servicemanager.";
-
- // Create a message loop.
- base::MessageLoopForIO messageLoopForIo;
- brillo::BaseMessageLoop messageLoop{&messageLoopForIo};
-
- // Initialize a binder watcher.
- brillo::BinderWatcher watcher(&messageLoop);
- watcher.Init();
-
- // Run the message loop.
- messageLoop.Run();
-}
diff --git a/services/nativeperms/nativeperms.rc b/services/nativeperms/nativeperms.rc
deleted file mode 100644
index 704c0a2..0000000
--- a/services/nativeperms/nativeperms.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service nativeperms /system/bin/nativeperms
- class main
- user system
- group system
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f51fbb4..59ea9af 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -25,6 +25,7 @@
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -253,90 +254,20 @@
mActiveBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
}
-void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice,
- const ui::Transform& transform, const Rect& viewport,
- int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) {
- RETURN_IF_NO_HWC_LAYER(displayDevice);
-
- // Apply this display's projection's viewport to the visible region
- // before giving it to the HWC HAL.
- Region visible = transform.transform(visibleRegion.intersect(viewport));
-
- const auto outputLayer = findOutputLayerForDisplay(displayDevice);
- LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
-
- auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
- auto error = hwcLayer->setVisibleRegion(visible);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- visible.dump(LOG_TAG);
- }
- outputLayer->editState().visibleRegion = visible;
-
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
-
- error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- surfaceDamageRegion.dump(LOG_TAG);
- }
- layerCompositionState.surfaceDamage = surfaceDamageRegion;
+void BufferLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ Layer::latchPerFrameState(compositionState);
// Sideband layers
- if (layerCompositionState.sidebandStream.get()) {
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::SIDEBAND);
- ALOGV("[%s] Requesting Sideband composition", mName.string());
- error = hwcLayer->setSidebandStream(layerCompositionState.sidebandStream->handle());
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
- layerCompositionState.sidebandStream->handle(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- layerCompositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
- return;
- }
-
- // Device or Cursor layers
- if (mPotentialCursor) {
- ALOGV("[%s] Requesting Cursor composition", mName.string());
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::CURSOR);
+ if (compositionState.sidebandStream.get()) {
+ compositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
} else {
- ALOGV("[%s] Requesting Device composition", mName.string());
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::DEVICE);
+ // Normal buffer layers
+ compositionState.hdrMetadata = getDrawingHdrMetadata();
+ compositionState.compositionType = mPotentialCursor
+ ? Hwc2::IComposerClient::Composition::CURSOR
+ : Hwc2::IComposerClient::Composition::DEVICE;
}
-
- ui::Dataspace dataspace = isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN
- ? targetDataspace
- : mCurrentDataSpace;
- error = hwcLayer->setDataspace(dataspace);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- const HdrMetadata& metadata = getDrawingHdrMetadata();
- error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata, metadata);
- if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
- ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- error = hwcLayer->setColorTransform(getColorTransform());
- if (error == HWC2::Error::Unsupported) {
- // If per layer color transform is not supported, we use GPU composition.
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::CLIENT);
- } else if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
- layerCompositionState.dataspace = mCurrentDataSpace;
- layerCompositionState.colorTransform = getColorTransform();
- layerCompositionState.hdrMetadata = metadata;
-
- setHwcLayerBuffer(displayDevice);
}
bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
@@ -395,7 +326,8 @@
return true;
}
-bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) {
ATRACE_CALL();
bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
@@ -430,12 +362,12 @@
const bool oldOpacity = isOpaque(s);
sp<GraphicBuffer> oldBuffer = mActiveBuffer;
- if (!allTransactionsSignaled()) {
+ if (!allTransactionsSignaled(expectedPresentTime)) {
mFlinger->setTransactionFlags(eTraversalNeeded);
return false;
}
- status_t err = updateTexImage(recomputeVisibleRegions, latchTime);
+ status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime);
if (err != NO_ERROR) {
return false;
}
@@ -540,10 +472,10 @@
}
// transaction
-void BufferLayer::notifyAvailableFrames() {
- const auto headFrameNumber = getHeadFrameNumber();
+void BufferLayer::notifyAvailableFrames(nsecs_t expectedPresentTime) {
+ const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime);
const bool headFenceSignaled = fenceHasSignaled();
- const bool presentTimeIsCurrent = framePresentTimeIsCurrent();
+ const bool presentTimeIsCurrent = framePresentTimeIsCurrent(expectedPresentTime);
Mutex::Autolock lock(mLocalSyncPointMutex);
for (auto& point : mLocalSyncPoints) {
if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled &&
@@ -591,8 +523,8 @@
}
// h/w composer set-up
-bool BufferLayer::allTransactionsSignaled() {
- auto headFrameNumber = getHeadFrameNumber();
+bool BufferLayer::allTransactionsSignaled(nsecs_t expectedPresentTime) {
+ const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime);
bool matchingFramesFound = false;
bool allTransactionsApplied = true;
Mutex::Autolock lock(mLocalSyncPointMutex);
@@ -658,9 +590,9 @@
sourceCrop.getWidth() != displayFrame.getWidth();
}
-uint64_t BufferLayer::getHeadFrameNumber() const {
+uint64_t BufferLayer::getHeadFrameNumber(nsecs_t expectedPresentTime) const {
if (hasFrameUpdate()) {
- return getFrameNumber();
+ return getFrameNumber(expectedPresentTime);
} else {
return mCurrentFrameNumber;
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index b679380..bb0205d 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -82,10 +82,6 @@
bool isHdrY410() const override;
- void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) override;
-
bool onPreComposition(nsecs_t refreshStartTime) override;
bool onPostComposition(const std::optional<DisplayId>& displayId,
const std::shared_ptr<FenceTime>& glDoneFence,
@@ -96,11 +92,12 @@
// the visible regions need to be recomputed (this is a fairly heavy
// operation, so this should be set only if needed). Typically this is used
// to figure out if the content or size of a surface has changed.
- bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+ bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) override;
bool isBufferLatched() const override { return mRefreshPending; }
- void notifyAvailableFrames() override;
+ void notifyAvailableFrames(nsecs_t expectedPresentTime) override;
bool hasReadyFrame() const override;
@@ -114,7 +111,7 @@
// -----------------------------------------------------------------------
private:
virtual bool fenceHasSignaled() const = 0;
- virtual bool framePresentTimeIsCurrent() const = 0;
+ virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0;
virtual nsecs_t getDesiredPresentTime() = 0;
virtual std::shared_ptr<FenceTime> getCurrentFenceTime() const = 0;
@@ -129,7 +126,7 @@
virtual int getDrawingApi() const = 0;
virtual PixelFormat getPixelFormat() const = 0;
- virtual uint64_t getFrameNumber() const = 0;
+ virtual uint64_t getFrameNumber(nsecs_t expectedPresentTime) const = 0;
virtual bool getAutoRefresh() const = 0;
virtual bool getSidebandStreamChanged() const = 0;
@@ -142,21 +139,22 @@
virtual void setFilteringEnabled(bool enabled) = 0;
virtual status_t bindTextureImage() = 0;
- virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0;
+ virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) = 0;
virtual status_t updateActiveBuffer() = 0;
virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
- virtual void setHwcLayerBuffer(const sp<const DisplayDevice>& displayDevice) = 0;
-
protected:
+ void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const override;
+
// Loads the corresponding system property once per process
static bool latchUnsignaledBuffers();
// Check all of the local sync points to ensure that all transactions
// which need to have been applied prior to the frame which is about to
// be latched have signaled
- bool allTransactionsSignaled();
+ bool allTransactionsSignaled(nsecs_t expectedPresentTime);
static bool getOpacityForFormat(uint32_t format);
@@ -175,7 +173,7 @@
// Returns true if this layer requires filtering
bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const;
- uint64_t getHeadFrameNumber() const;
+ uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
uint32_t mCurrentScalingMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index f35a4fd..12be00f 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -137,13 +137,13 @@
return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
}
-bool BufferQueueLayer::framePresentTimeIsCurrent() const {
+bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const {
if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
return true;
}
Mutex::Autolock lock(mQueueItemLock);
- return mQueueItems[0].mTimestamp <= mFlinger->getExpectedPresentTime();
+ return mQueueItems[0].mTimestamp <= expectedPresentTime;
}
nsecs_t BufferQueueLayer::getDesiredPresentTime() {
@@ -196,13 +196,11 @@
return mFormat;
}
-uint64_t BufferQueueLayer::getFrameNumber() const {
+uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const {
Mutex::Autolock lock(mQueueItemLock);
uint64_t frameNumber = mQueueItems[0].mFrameNumber;
// The head of the queue will be dropped if there are signaled and timely frames behind it
- nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime();
-
if (isRemovedFromCurrentState()) {
expectedPresentTime = 0;
}
@@ -268,7 +266,8 @@
return mConsumer->bindTextureImage();
}
-status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) {
// This boolean is used to make sure that SurfaceFlinger's shadow copy
// of the buffer queue isn't modified when the buffer queue is returning
// BufferItem's that weren't actually queued. This can happen in shared
@@ -279,8 +278,6 @@
getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
getTransformToDisplayInverse(), mFreezeGeometryUpdates);
- nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime();
-
if (isRemovedFromCurrentState()) {
expectedPresentTime = 0;
}
@@ -379,7 +376,6 @@
mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence);
auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
layerCompositionState.buffer = mActiveBuffer;
- layerCompositionState.bufferSlot = mActiveBufferSlot;
if (mActiveBuffer == nullptr) {
// this can only happen if the very first buffer was rejected.
@@ -399,32 +395,17 @@
return NO_ERROR;
}
-void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- LOG_FATAL_IF(!outputLayer->getState.hwc);
- auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
-
- uint32_t hwcSlot = 0;
- sp<GraphicBuffer> hwcBuffer;
-
- // INVALID_BUFFER_SLOT is used to identify BufferStateLayers. Default to 0
- // for BufferQueueLayers
- int slot = (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot;
- (*outputLayer->editState().hwc)
- .hwcBufferCache.getHwcBuffer(slot, mActiveBuffer, &hwcSlot, &hwcBuffer);
-
- auto acquireFence = mConsumer->getCurrentFence();
- auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), mActiveBuffer->handle,
- to_string(error).c_str(), static_cast<int32_t>(error));
+void BufferQueueLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ BufferLayer::latchPerFrameState(compositionState);
+ if (compositionState.compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) {
+ return;
}
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
- layerCompositionState.bufferSlot = mActiveBufferSlot;
- layerCompositionState.buffer = mActiveBuffer;
- layerCompositionState.acquireFence = acquireFence;
+ compositionState.buffer = mActiveBuffer;
+ compositionState.bufferSlot =
+ (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot;
+ compositionState.acquireFence = mConsumer->getCurrentFence();
}
// -----------------------------------------------------------------------
@@ -434,7 +415,7 @@
void BufferQueueLayer::fakeVsync() {
mRefreshPending = false;
bool ignored = false;
- latchBuffer(ignored, systemTime());
+ latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */);
usleep(16000);
releasePendingBuffer(systemTime());
}
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 7def33a..231a531 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -61,7 +61,7 @@
// -----------------------------------------------------------------------
public:
bool fenceHasSignaled() const override;
- bool framePresentTimeIsCurrent() const override;
+ bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
private:
nsecs_t getDesiredPresentTime() override;
@@ -77,7 +77,7 @@
int getDrawingApi() const override;
PixelFormat getPixelFormat() const override;
- uint64_t getFrameNumber() const override;
+ uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
bool getAutoRefresh() const override;
bool getSidebandStreamChanged() const override;
@@ -89,12 +89,13 @@
void setFilteringEnabled(bool enabled) override;
status_t bindTextureImage() override;
- status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+ status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) override;
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& displayDevice) override;
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
// -----------------------------------------------------------------------
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 4b01301..0f26211 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -216,7 +216,7 @@
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
- mFlinger->mTimeStats->setPostTime(getSequence(), getFrameNumber(), getName().c_str(), postTime);
+ mFlinger->mTimeStats->setPostTime(getSequence(), mFrameNumber, getName().c_str(), postTime);
mDesiredPresentTime = desiredPresentTime;
if (mFlinger->mUseSmart90ForVideo) {
@@ -369,12 +369,12 @@
return getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
}
-bool BufferStateLayer::framePresentTimeIsCurrent() const {
+bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const {
if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
return true;
}
- return mDesiredPresentTime <= mFlinger->getExpectedPresentTime();
+ return mDesiredPresentTime <= expectedPresentTime;
}
nsecs_t BufferStateLayer::getDesiredPresentTime() {
@@ -446,7 +446,7 @@
return mActiveBuffer->format;
}
-uint64_t BufferStateLayer::getFrameNumber() const {
+uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const {
return mFrameNumber;
}
@@ -494,7 +494,8 @@
return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence);
}
-status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime) {
+status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
+ nsecs_t /*expectedPresentTime*/) {
const State& s(getDrawingState());
if (!s.buffer) {
@@ -528,7 +529,7 @@
ALOGE("[%s] rejecting buffer: "
"bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
mName.string(), bufferWidth, bufferHeight, s.active.w, s.active.h);
- mFlinger->mTimeStats->removeTimeRecord(layerID, getFrameNumber());
+ mFlinger->mTimeStats->removeTimeRecord(layerID, mFrameNumber);
return BAD_VALUE;
}
@@ -550,8 +551,8 @@
}
}
- mFlinger->mTimeStats->setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime());
- mFlinger->mTimeStats->setLatchTime(layerID, getFrameNumber(), latchTime);
+ mFlinger->mTimeStats->setAcquireFence(layerID, mFrameNumber, getCurrentFenceTime());
+ mFlinger->mTimeStats->setLatchTime(layerID, mFrameNumber, latchTime);
mCurrentStateModified = false;
@@ -569,7 +570,6 @@
mActiveBufferFence = s.acquireFence;
auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
layerCompositionState.buffer = mActiveBuffer;
- layerCompositionState.bufferSlot = 0;
return NO_ERROR;
}
@@ -580,24 +580,18 @@
return NO_ERROR;
}
-void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
- auto& hwcInfo = *outputLayer->editState().hwc;
- auto& hwcLayer = hwcInfo.hwcLayer;
+void BufferStateLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ BufferLayer::latchPerFrameState(compositionState);
+ if (compositionState.compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) {
+ return;
+ }
const State& s(getDrawingState());
- uint32_t hwcSlot;
- sp<GraphicBuffer> buffer;
- hwcInfo.hwcBufferCache.getHwcBuffer(mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId),
- s.buffer, &hwcSlot, &buffer);
-
- auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
- s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
- }
+ compositionState.buffer = s.buffer;
+ compositionState.bufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId);
+ compositionState.acquireFence = s.acquireFence;
mFrameNumber++;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index db8ae0d..5e5b9b0 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -100,7 +100,7 @@
// Interface implementation for BufferLayer
// -----------------------------------------------------------------------
bool fenceHasSignaled() const override;
- bool framePresentTimeIsCurrent() const override;
+ bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
// Inherit from ClientCache::ErasedRecipient
void bufferErased(const client_cache_t& clientCacheId) override;
@@ -119,7 +119,7 @@
int getDrawingApi() const override;
PixelFormat getPixelFormat() const override;
- uint64_t getFrameNumber() const override;
+ uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
bool getAutoRefresh() const override;
bool getSidebandStreamChanged() const override;
@@ -131,12 +131,13 @@
void setFilteringEnabled(bool enabled) override;
status_t bindTextureImage() override;
- status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+ status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) override;
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
private:
friend class SlotGenerationTest;
@@ -151,11 +152,11 @@
std::atomic<bool> mSidebandStreamChanged{false};
- uint32_t mFrameNumber{0};
+ mutable uint32_t mFrameNumber{0};
sp<Fence> mPreviousReleaseFence;
- bool mCurrentStateModified = false;
+ mutable bool mCurrentStateModified = false;
bool mReleasePreviousBuffer = false;
nsecs_t mCallbackHandleAcquireTime = -1;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index fcc2d97..f15957a 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -18,6 +18,8 @@
#undef LOG_TAG
#define LOG_TAG "ColorLayer"
+#include "ColorLayer.h"
+
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -26,6 +28,7 @@
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -34,7 +37,6 @@
#include <utils/Errors.h>
#include <utils/Log.h>
-#include "ColorLayer.h"
#include "DisplayDevice.h"
#include "SurfaceFlinger.h"
@@ -91,75 +93,12 @@
return true;
}
-void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display,
- const ui::Transform& transform, const Rect& viewport,
- int32_t /* supportedPerFrameMetadata */,
- const ui::Dataspace targetDataspace) {
- RETURN_IF_NO_HWC_LAYER(display);
+void ColorLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ Layer::latchPerFrameState(compositionState);
- Region visible = transform.transform(visibleRegion.intersect(viewport));
-
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
-
- auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
-
- auto error = hwcLayer->setVisibleRegion(visible);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- visible.dump(LOG_TAG);
- }
- outputLayer->editState().visibleRegion = visible;
-
- setCompositionType(display, Hwc2::IComposerClient::Composition::SOLID_COLOR);
-
- const ui::Dataspace dataspace =
- isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN ? targetDataspace
- : mCurrentDataSpace;
- error = hwcLayer->setDataspace(dataspace);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
- layerCompositionState.dataspace = mCurrentDataSpace;
-
- half4 color = getColor();
- error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
- static_cast<uint8_t>(std::round(255.0f * color.g)),
- static_cast<uint8_t>(std::round(255.0f * color.b)), 255});
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- layerCompositionState.color = {static_cast<uint8_t>(std::round(255.0f * color.r)),
- static_cast<uint8_t>(std::round(255.0f * color.g)),
- static_cast<uint8_t>(std::round(255.0f * color.b)), 255};
-
- // Clear out the transform, because it doesn't make sense absent a source buffer
- error = hwcLayer->setTransform(HWC2::Transform::None);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- outputLayer->editState().bufferTransform = static_cast<Hwc2::Transform>(0);
-
- error = hwcLayer->setColorTransform(getColorTransform());
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
- layerCompositionState.colorTransform = getColorTransform();
-
- error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- surfaceDamageRegion.dump(LOG_TAG);
- }
- layerCompositionState.surfaceDamage = surfaceDamageRegion;
+ compositionState.color = getColor();
+ compositionState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
}
void ColorLayer::commitTransaction(const State& stateToCommit) {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 53d5b5b..2483ff0 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -37,10 +37,6 @@
bool setDataspace(ui::Dataspace dataspace) override;
- void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) override;
-
void commitTransaction(const State& stateToCommit) override;
bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
@@ -52,6 +48,8 @@
renderengine::LayerSettings& layer);
private:
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+
std::shared_ptr<compositionengine::Layer> mCompositionLayer;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
index 896f8aa..31d6365 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
@@ -18,6 +18,8 @@
#include <memory>
+#include <utils/Timers.h>
+
namespace android {
class HWComposer;
@@ -31,6 +33,7 @@
class Display;
class Layer;
+struct CompositionRefreshArgs;
struct DisplayCreationArgs;
struct LayerCreationArgs;
@@ -51,6 +54,12 @@
virtual renderengine::RenderEngine& getRenderEngine() const = 0;
virtual void setRenderEngine(std::unique_ptr<renderengine::RenderEngine>) = 0;
+
+ virtual bool needsAnotherUpdate() const = 0;
+ virtual nsecs_t getLastFrameRefreshTimestamp() const = 0;
+
+ // TODO(b/121291683): These will become private/internal
+ virtual void preComposition(CompositionRefreshArgs&) = 0;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
new file mode 100644
index 0000000..20f131e
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -0,0 +1,40 @@
+/*
+ * 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/Display.h>
+#include <compositionengine/Layer.h>
+
+namespace android::compositionengine {
+
+using Layers = std::vector<std::shared_ptr<compositionengine::Layer>>;
+using Outputs = std::vector<std::shared_ptr<compositionengine::Output>>;
+
+/**
+ * A parameter object for refreshing a set of outputs
+ */
+struct CompositionRefreshArgs {
+ // All the outputs being refreshed
+ Outputs outputs;
+
+ // All the layers that are potentially visible in the outputs. The order of
+ // the layers is important, and should be in traversal order from back to
+ // front.
+ Layers layers;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
index e2a0d42..d93bfa3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include <string>
#include <ui/GraphicTypes.h>
@@ -75,6 +76,13 @@
// Gets the supported HDR capabilities for the profile
virtual const HdrCapabilities& getHdrCapabilities() const = 0;
+ // Returns true if HWC for this profile supports the dataspace
+ virtual bool isDataspaceSupported(ui::Dataspace) const = 0;
+
+ // Returns the target dataspace for picked color mode and dataspace
+ virtual ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace,
+ ui::Dataspace colorSpaceAgnosticDataspace) const = 0;
+
// Debugging
virtual void dump(std::string&) const = 0;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
index 8cb9203..451608b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
@@ -21,11 +21,7 @@
#include <utils/StrongPointer.h>
-namespace android {
-
-typedef int64_t nsecs_t;
-
-namespace compositionengine {
+namespace android::compositionengine {
class Display;
class LayerFE;
@@ -62,5 +58,4 @@
virtual void dump(std::string& result) const = 0;
};
-} // namespace compositionengine
-} // namespace android
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 9f635b9..1f2cae9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -17,6 +17,7 @@
#pragma once
#include <utils/RefBase.h>
+#include <utils/Timers.h>
namespace android {
@@ -30,6 +31,11 @@
// of the front-end layer
class LayerFE : public virtual RefBase {
public:
+ // Called before composition starts. Should return true if this layer has
+ // pending updates which would require an extra display refresh cycle to
+ // process.
+ virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
+
// Latches the output-independent state. If includeGeometry is false, the
// geometry state can be skipped.
virtual void latchCompositionState(LayerFECompositionState&, bool includeGeometry) const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index e6ee078..d96d58c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -36,9 +36,9 @@
* Used by LayerFE::getCompositionState
*/
struct LayerFECompositionState {
- // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
- // value recomputed / set every frame.
- Region geomVisibleRegion;
+ // If set to true, forces client composition on all output layers until
+ // the next geometry change.
+ bool forceClientComposition{false};
/*
* Geometry state
@@ -56,6 +56,10 @@
Region geomActiveTransparentRegion;
FloatRect geomLayerBounds;
+ // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
+ // value recomputed / set every frame.
+ Region geomVisibleRegion;
+
/*
* Presentation
*/
@@ -93,12 +97,16 @@
sp<NativeHandle> sidebandStream;
// The color for this layer
- Hwc2::IComposerClient::Color color;
+ half4 color;
/*
* Per-frame presentation state
*/
+ // If true, this layer will use the dataspace chosen for the output and
+ // ignore the dataspace value just below
+ bool isColorspaceAgnostic{false};
+
// The dataspace for this layer
ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
@@ -107,6 +115,7 @@
// The color transform
mat4 colorTransform;
+ bool colorTransformIsIdentity{true};
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 54e6bd6..5b9e282 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -46,6 +46,7 @@
class Output {
public:
using OutputLayers = std::vector<std::unique_ptr<compositionengine::OutputLayer>>;
+ using ReleasedLayers = std::vector<wp<LayerFE>>;
virtual ~Output();
@@ -71,7 +72,8 @@
virtual void setColorTransform(const mat4&) = 0;
// Sets the output color mode
- virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) = 0;
+ virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent,
+ ui::Dataspace colorSpaceAgnosticDataspace) = 0;
// Outputs a string with a state dump
virtual void dump(std::string&) const = 0;
@@ -130,6 +132,12 @@
// Gets the ordered set of output layers for this output
virtual const OutputLayers& getOutputLayersOrderedByZ() const = 0;
+ // Sets the new set of layers being released this frame.
+ virtual void setReleasedLayers(ReleasedLayers&&) = 0;
+
+ // Takes (moves) the set of layers being released this frame.
+ virtual ReleasedLayers takeReleasedLayers() = 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
index cd63b57..d3a4e09 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -71,7 +71,7 @@
// Writes the geometry state to the HWC, or does nothing if this layer does
// not use the HWC. If includeGeometry is false, the geometry state can be
// skipped.
- virtual void writeStateToHWC(bool includeGeometry) const = 0;
+ virtual void writeStateToHWC(bool includeGeometry) = 0;
// Debugging
virtual void dump(std::string& result) const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
index b01eb64..96e609d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -36,9 +36,19 @@
renderengine::RenderEngine& getRenderEngine() const override;
void setRenderEngine(std::unique_ptr<renderengine::RenderEngine>) override;
+ bool needsAnotherUpdate() const override;
+ nsecs_t getLastFrameRefreshTimestamp() const override;
+
+ void preComposition(CompositionRefreshArgs&) override;
+
+ // Testing
+ void setNeedsAnotherUpdateForTest(bool);
+
private:
std::unique_ptr<HWComposer> mHwComposer;
std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
+ bool mNeedsAnotherUpdate = false;
+ nsecs_t mRefreshStartTime = 0;
};
std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine();
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 0e20c43..1265533 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -39,7 +39,7 @@
// compositionengine::Output overrides
void dump(std::string&) const override;
void setColorTransform(const mat4&) override;
- void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+ void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
// compositionengine::Display overrides
const std::optional<DisplayId>& getId() const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
index 49c2d2c..e84a36e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
@@ -54,6 +54,8 @@
bool hasDolbyVisionSupport() const override;
const HdrCapabilities& getHdrCapabilities() const override;
+ bool isDataspaceSupported(ui::Dataspace) const override;
+ ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace) const override;
void dump(std::string&) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index b1d1f42..20812d2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -45,7 +45,7 @@
void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
void setColorTransform(const mat4&) override;
- void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+ void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
void dump(std::string&) const override;
@@ -72,6 +72,9 @@
void setOutputLayersOrderedByZ(OutputLayers&&) override;
const OutputLayers& getOutputLayersOrderedByZ() const override;
+ void setReleasedLayers(ReleasedLayers&&) override;
+ ReleasedLayers takeReleasedLayers() override;
+
// Testing
void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
@@ -93,6 +96,7 @@
std::unique_ptr<compositionengine::RenderSurface> mRenderSurface;
OutputLayers mOutputLayersOrderedByZ;
+ ReleasedLayers mReleasedLayers;
};
} // namespace impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 0c47eb5..45b8308 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -88,9 +88,12 @@
// Current active render intent
ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC};
- // Current active dstaspace
+ // Current active dataspace
ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+ // Current target dataspace
+ ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN};
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 6a4818f..708f3a1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -26,7 +26,11 @@
#include "DisplayHardware/DisplayIdentification.h"
-namespace android::compositionengine::impl {
+namespace android::compositionengine {
+
+struct LayerFECompositionState;
+
+namespace impl {
class OutputLayer : public compositionengine::OutputLayer {
public:
@@ -44,7 +48,7 @@
OutputLayerCompositionState& editState() override;
void updateCompositionState(bool) override;
- void writeStateToHWC(bool) const override;
+ void writeStateToHWC(bool) override;
void dump(std::string& result) const override;
@@ -54,6 +58,14 @@
private:
Rect calculateInitialCrop() const;
+ void writeOutputDependentGeometryStateToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition);
+ void writeOutputIndependentGeometryStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeOutputDependentPerFrameStateToHWC(HWC2::Layer*);
+ void writeOutputIndependentPerFrameStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeSolidColorStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition);
const compositionengine::Output& mOutput;
std::shared_ptr<compositionengine::Layer> mLayer;
@@ -66,4 +78,5 @@
const CompositionEngine&, std::optional<DisplayId>, const compositionengine::Output&,
std::shared_ptr<compositionengine::Layer>, sp<compositionengine::LayerFE>);
-} // namespace android::compositionengine::impl
+} // namespace impl
+} // namespace android::compositionengine
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index b78e9e0..de0f08a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -23,6 +23,7 @@
#include <compositionengine/impl/HwcBufferCache.h>
#include <renderengine/Mesh.h>
#include <ui/FloatRect.h>
+#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -57,6 +58,9 @@
// The buffer transform to use for this layer o on this output.
Hwc2::Transform bufferTransform{static_cast<Hwc2::Transform>(0)};
+ // The dataspace for this layer
+ ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+
// The Z order index of this layer on this output
uint32_t z;
@@ -70,7 +74,7 @@
// The HWC Layer backing this layer
std::shared_ptr<HWC2::Layer> hwcLayer;
- // The HWC composition type for this layer
+ // The most recently set HWC composition type for this layer
Hwc2::IComposerClient::Composition hwcCompositionType{
Hwc2::IComposerClient::Composition::INVALID};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
index 0f57685..82ecec5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
@@ -17,6 +17,7 @@
#pragma once
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/DisplayCreationArgs.h>
#include <compositionengine/LayerCreationArgs.h>
#include <gmock/gmock.h>
@@ -39,6 +40,11 @@
MOCK_CONST_METHOD0(getRenderEngine, renderengine::RenderEngine&());
MOCK_METHOD1(setRenderEngine, void(std::unique_ptr<renderengine::RenderEngine>));
+
+ MOCK_CONST_METHOD0(needsAnotherUpdate, bool());
+ MOCK_CONST_METHOD0(getLastFrameRefreshTimestamp, nsecs_t());
+
+ MOCK_METHOD1(preComposition, void(CompositionRefreshArgs&));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
index 8056c9d..1aaebea 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
@@ -42,6 +42,9 @@
MOCK_CONST_METHOD0(hasDolbyVisionSupport, bool());
MOCK_CONST_METHOD0(getHdrCapabilities, const HdrCapabilities&());
+ MOCK_CONST_METHOD1(isDataspaceSupported, bool(ui::Dataspace));
+ MOCK_CONST_METHOD3(getTargetDataspace,
+ ui::Dataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index aab18db..952f702 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -30,6 +30,8 @@
LayerFE();
virtual ~LayerFE();
+ MOCK_METHOD1(onPreComposition, bool(nsecs_t));
+
MOCK_CONST_METHOD2(latchCompositionState, void(LayerFECompositionState&, bool));
MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index d0e7b19..924d72c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -41,17 +41,18 @@
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
MOCK_METHOD1(setColorTransform, void(const mat4&));
- MOCK_METHOD3(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent));
+ MOCK_METHOD4(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_CONST_METHOD0(getName, const std::string&());
MOCK_METHOD1(setName, void(const std::string&));
- MOCK_CONST_METHOD0(getDisplayColorProfile, DisplayColorProfile*());
- MOCK_METHOD1(setDisplayColorProfile, void(std::unique_ptr<DisplayColorProfile>));
+ MOCK_CONST_METHOD0(getDisplayColorProfile, compositionengine::DisplayColorProfile*());
+ MOCK_METHOD1(setDisplayColorProfile,
+ void(std::unique_ptr<compositionengine::DisplayColorProfile>));
- MOCK_CONST_METHOD0(getRenderSurface, RenderSurface*());
- MOCK_METHOD1(setRenderSurface, void(std::unique_ptr<RenderSurface>));
+ MOCK_CONST_METHOD0(getRenderSurface, compositionengine::RenderSurface*());
+ MOCK_METHOD1(setRenderSurface, void(std::unique_ptr<compositionengine::RenderSurface>));
MOCK_CONST_METHOD0(getState, const OutputCompositionState&());
MOCK_METHOD0(editState, OutputCompositionState&());
@@ -65,8 +66,12 @@
std::unique_ptr<compositionengine::OutputLayer>(
std::optional<DisplayId>, std::shared_ptr<compositionengine::Layer>,
sp<compositionengine::LayerFE>));
+
MOCK_METHOD1(setOutputLayersOrderedByZ, void(OutputLayers&&));
MOCK_CONST_METHOD0(getOutputLayersOrderedByZ, OutputLayers&());
+
+ MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&));
+ MOCK_METHOD0(takeReleasedLayers, ReleasedLayers());
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 29cd08a..dab8b9d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -39,7 +39,7 @@
MOCK_METHOD0(editState, impl::OutputLayerCompositionState&());
MOCK_METHOD1(updateCompositionState, void(bool));
- MOCK_CONST_METHOD1(writeStateToHWC, void(bool));
+ MOCK_METHOD1(writeStateToHWC, void(bool));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index cb08b81..9558266 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -14,10 +14,13 @@
* limitations under the License.
*/
+#include <compositionengine/CompositionRefreshArgs.h>
+#include <compositionengine/LayerFE.h>
#include <compositionengine/impl/CompositionEngine.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/Layer.h>
#include <renderengine/RenderEngine.h>
+#include <utils/Trace.h>
#include "DisplayHardware/HWComposer.h"
@@ -59,5 +62,35 @@
mRenderEngine = std::move(renderEngine);
}
+bool CompositionEngine::needsAnotherUpdate() const {
+ return mNeedsAnotherUpdate;
+}
+
+nsecs_t CompositionEngine::getLastFrameRefreshTimestamp() const {
+ return mRefreshStartTime;
+}
+
+void CompositionEngine::preComposition(CompositionRefreshArgs& args) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ bool needsAnotherUpdate = false;
+
+ mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ for (auto& layer : args.layers) {
+ sp<compositionengine::LayerFE> layerFE = layer->getLayerFE();
+ if (layerFE && layerFE->onPreComposition(mRefreshStartTime)) {
+ needsAnotherUpdate = true;
+ }
+ }
+
+ mNeedsAnotherUpdate = needsAnotherUpdate;
+}
+
+void CompositionEngine::setNeedsAnotherUpdateForTest(bool value) {
+ mNeedsAnotherUpdate = value;
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index f9d70e3..8520d70 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -74,9 +74,14 @@
}
void Display::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
- ui::RenderIntent renderIntent) {
+ ui::RenderIntent renderIntent,
+ ui::Dataspace colorSpaceAgnosticDataspace) {
+ ui::Dataspace targetDataspace =
+ getDisplayColorProfile()->getTargetDataspace(mode, dataspace,
+ colorSpaceAgnosticDataspace);
+
if (mode == getState().colorMode && dataspace == getState().dataspace &&
- renderIntent == getState().renderIntent) {
+ renderIntent == getState().renderIntent && targetDataspace == getState().targetDataspace) {
return;
}
@@ -85,7 +90,7 @@
return;
}
- Output::setColorMode(mode, dataspace, renderIntent);
+ Output::setColorMode(mode, dataspace, renderIntent, colorSpaceAgnosticDataspace);
auto& hwc = getCompositionEngine().getHwComposer();
hwc.setActiveColorMode(*mId, mode, renderIntent);
diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
index 130ab1d..5ef9097 100644
--- a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
@@ -64,6 +64,12 @@
RenderIntent::TONE_MAP_COLORIMETRIC,
};
+// Returns true if the given colorMode is considered an HDR color mode
+bool isHdrColorMode(const ColorMode colorMode) {
+ return std::any_of(std::begin(sHdrColorModes), std::end(sHdrColorModes),
+ [colorMode](ColorMode hdrColorMode) { return hdrColorMode == colorMode; });
+}
+
// map known color mode to dataspace
Dataspace colorModeToDataspace(ColorMode mode) {
switch (mode) {
@@ -90,13 +96,7 @@
candidates.push_back(mode);
// check if mode is HDR
- bool isHdr = false;
- for (auto hdrMode : sHdrColorModes) {
- if (hdrMode == mode) {
- isHdr = true;
- break;
- }
- }
+ bool isHdr = isHdrColorMode(mode);
// add other HDR candidates when mode is HDR
if (isHdr) {
@@ -376,6 +376,32 @@
}
}
+bool DisplayColorProfile::isDataspaceSupported(Dataspace dataspace) const {
+ switch (dataspace) {
+ case Dataspace::BT2020_PQ:
+ case Dataspace::BT2020_ITU_PQ:
+ return hasHDR10Support();
+
+ case Dataspace::BT2020_HLG:
+ case Dataspace::BT2020_ITU_HLG:
+ return hasHLGSupport();
+
+ default:
+ return true;
+ }
+}
+
+ui::Dataspace DisplayColorProfile::getTargetDataspace(ColorMode mode, Dataspace dataspace,
+ Dataspace colorSpaceAgnosticDataspace) const {
+ if (isHdrColorMode(mode)) {
+ return Dataspace::UNKNOWN;
+ }
+ if (colorSpaceAgnosticDataspace != ui::Dataspace::UNKNOWN) {
+ return colorSpaceAgnosticDataspace;
+ }
+ return dataspace;
+}
+
void DisplayColorProfile::dump(std::string& out) const {
out.append(" Composition Display Color State:");
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
index 40c4da9..37d6eaa 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
@@ -24,9 +24,10 @@
using android::compositionengine::impl::dumpVal;
-void dumpVal(std::string& out, const char* name, Hwc2::IComposerClient::Color value) {
+void dumpVal(std::string& out, const char* name, half4 value) {
using android::base::StringAppendF;
- StringAppendF(&out, "%s=[%d %d %d] ", name, value.r, value.g, value.b);
+ StringAppendF(&out, "%s=[%f %f %f] ", name, static_cast<float>(value.r),
+ static_cast<float>(value.g), static_cast<float>(value.b));
}
void dumpFrontEnd(std::string& out, const LayerFECompositionState& state) {
@@ -60,8 +61,8 @@
dumpVal(out, "composition type", toString(state.compositionType), state.compositionType);
out.append("\n buffer: ");
+ dumpVal(out, "bufferSlot", state.bufferSlot);
dumpVal(out, "buffer", state.buffer.get());
- dumpVal(out, "slot", state.bufferSlot);
out.append("\n ");
dumpVal(out, "sideband stream", state.sidebandStream.get());
@@ -70,6 +71,7 @@
dumpVal(out, "color", state.color);
out.append("\n ");
+ dumpVal(out, "isColorspaceAgnostic", state.isColorspaceAgnostic);
dumpVal(out, "dataspace", toString(state.dataspace), state.dataspace);
dumpVal(out, "hdr metadata types", state.hdrMetadata.validTypes);
dumpVal(out, "colorTransform", state.colorTransform);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 01b5781..845e3c6 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -104,15 +104,21 @@
}
void Output::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
- ui::RenderIntent renderIntent) {
+ ui::RenderIntent renderIntent,
+ ui::Dataspace colorSpaceAgnosticDataspace) {
+ ui::Dataspace targetDataspace =
+ getDisplayColorProfile()->getTargetDataspace(mode, dataspace,
+ colorSpaceAgnosticDataspace);
+
if (mState.colorMode == mode && mState.dataspace == dataspace &&
- mState.renderIntent == renderIntent) {
+ mState.renderIntent == renderIntent && mState.targetDataspace == targetDataspace) {
return;
}
mState.colorMode = mode;
mState.dataspace = dataspace;
mState.renderIntent = renderIntent;
+ mState.targetDataspace = targetDataspace;
mRenderSurface->setBufferDataspace(dataspace);
@@ -236,6 +242,14 @@
return mOutputLayersOrderedByZ;
}
+void Output::setReleasedLayers(Output::ReleasedLayers&& layers) {
+ mReleasedLayers = std::move(layers);
+}
+
+Output::ReleasedLayers Output::takeReleasedLayers() {
+ return std::move(mReleasedLayers);
+}
+
void Output::dirtyEntireOutput() {
mState.dirtyRegion.set(mState.bounds);
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 9549054..0b15dad 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -44,6 +44,7 @@
dumpVal(out, "renderIntent", toString(renderIntent), renderIntent);
dumpVal(out, "dataspace", toString(dataspace), dataspace);
dumpVal(out, "colorTransform", colorTransform);
+ dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace);
out.append("\n");
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 5ce72b0..ebfc704 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -16,6 +16,7 @@
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
#include <compositionengine/Output.h>
@@ -290,20 +291,43 @@
} // namespace impl
void OutputLayer::updateCompositionState(bool includeGeometry) {
+ const auto& layerFEState = mLayer->getState().frontEnd;
+ const auto& outputState = mOutput.getState();
+ const auto& profile = *mOutput.getDisplayColorProfile();
+
if (includeGeometry) {
mState.displayFrame = calculateOutputDisplayFrame();
mState.sourceCrop = calculateOutputSourceCrop();
mState.bufferTransform =
static_cast<Hwc2::Transform>(calculateOutputRelativeBufferTransform());
- if ((mLayer->getState().frontEnd.isSecure && !mOutput.getState().isSecure) ||
+ if ((layerFEState.isSecure && !outputState.isSecure) ||
(mState.bufferTransform & ui::Transform::ROT_INVALID)) {
mState.forceClientComposition = true;
}
}
+
+ // Determine the output dependent dataspace for this layer. If it is
+ // colorspace agnostic, it just uses the dataspace chosen for the output to
+ // avoid the need for color conversion.
+ mState.dataspace = layerFEState.isColorspaceAgnostic &&
+ outputState.targetDataspace != ui::Dataspace::UNKNOWN
+ ? outputState.targetDataspace
+ : layerFEState.dataspace;
+
+ // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
+ // value recomputed / set every frame.
+ mState.visibleRegion = outputState.transform.transform(
+ layerFEState.geomVisibleRegion.intersect(outputState.viewport));
+
+ // These are evaluated every frame as they can potentially change at any
+ // time.
+ if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(mState.dataspace)) {
+ mState.forceClientComposition = true;
+ }
}
-void OutputLayer::writeStateToHWC(bool includeGeometry) const {
+void OutputLayer::writeStateToHWC(bool includeGeometry) {
// Skip doing this if there is no HWC interface
if (!mState.hwc) {
return;
@@ -316,63 +340,213 @@
return;
}
+ const auto& outputIndependentState = mLayer->getState().frontEnd;
+ auto requestedCompositionType = outputIndependentState.compositionType;
+
if (includeGeometry) {
- // Output dependent state
+ writeOutputDependentGeometryStateToHWC(hwcLayer.get(), requestedCompositionType);
+ writeOutputIndependentGeometryStateToHWC(hwcLayer.get(), outputIndependentState);
+ }
- if (auto error = hwcLayer->setDisplayFrame(mState.displayFrame);
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
- mLayerFE->getDebugName(), mState.displayFrame.left, mState.displayFrame.top,
- mState.displayFrame.right, mState.displayFrame.bottom, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ writeOutputDependentPerFrameStateToHWC(hwcLayer.get());
+ writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), outputIndependentState);
- if (auto error = hwcLayer->setSourceCrop(mState.sourceCrop); error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
- "%s (%d)",
- mLayerFE->getDebugName(), mState.sourceCrop.left, mState.sourceCrop.top,
- mState.sourceCrop.right, mState.sourceCrop.bottom, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType);
+}
- if (auto error = hwcLayer->setZOrder(mState.z); error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set Z %u: %s (%d)", mLayerFE->getDebugName(), mState.z,
+void OutputLayer::writeOutputDependentGeometryStateToHWC(
+ HWC2::Layer* hwcLayer, Hwc2::IComposerClient::Composition requestedCompositionType) {
+ const auto& outputDependentState = getState();
+
+ if (auto error = hwcLayer->setDisplayFrame(outputDependentState.displayFrame);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
+ mLayerFE->getDebugName(), outputDependentState.displayFrame.left,
+ outputDependentState.displayFrame.top, outputDependentState.displayFrame.right,
+ outputDependentState.displayFrame.bottom, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setSourceCrop(outputDependentState.sourceCrop);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
+ "%s (%d)",
+ mLayerFE->getDebugName(), outputDependentState.sourceCrop.left,
+ outputDependentState.sourceCrop.top, outputDependentState.sourceCrop.right,
+ outputDependentState.sourceCrop.bottom, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setZOrder(outputDependentState.z); error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set Z %u: %s (%d)", mLayerFE->getDebugName(), outputDependentState.z,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ // Solid-color layers should always use an identity transform.
+ const auto bufferTransform =
+ requestedCompositionType != Hwc2::IComposerClient::Composition::SOLID_COLOR
+ ? outputDependentState.bufferTransform
+ : static_cast<Hwc2::Transform>(0);
+ if (auto error = hwcLayer->setTransform(static_cast<HWC2::Transform>(bufferTransform));
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set transform %s: %s (%d)", mLayerFE->getDebugName(),
+ toString(outputDependentState.bufferTransform).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeOutputIndependentGeometryStateToHWC(
+ HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) {
+ if (auto error = hwcLayer->setBlendMode(
+ static_cast<HWC2::BlendMode>(outputIndependentState.blendMode));
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set blend mode %s: %s (%d)", mLayerFE->getDebugName(),
+ toString(outputIndependentState.blendMode).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setPlaneAlpha(outputIndependentState.alpha);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set plane alpha %.3f: %s (%d)", mLayerFE->getDebugName(),
+ outputIndependentState.alpha, to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set info %s (%d)", mLayerFE->getDebugName(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) {
+ const auto& outputDependentState = getState();
+
+ // TODO(lpique): b/121291683 visibleRegion is output-dependent geometry
+ // state and should not change every frame.
+ if (auto error = hwcLayer->setVisibleRegion(outputDependentState.visibleRegion);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set visible region: %s (%d)", mLayerFE->getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ outputDependentState.visibleRegion.dump(LOG_TAG);
+ }
+
+ if (auto error = hwcLayer->setDataspace(outputDependentState.dataspace);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mLayerFE->getDebugName(),
+ outputDependentState.dataspace, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeOutputIndependentPerFrameStateToHWC(
+ HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) {
+ switch (auto error = hwcLayer->setColorTransform(outputIndependentState.colorTransform)) {
+ case HWC2::Error::None:
+ break;
+ case HWC2::Error::Unsupported:
+ editState().forceClientComposition = true;
+ break;
+ default:
+ ALOGE("[%s] Failed to set color transform: %s (%d)", mLayerFE->getDebugName(),
to_string(error).c_str(), static_cast<int32_t>(error));
- }
+ }
- if (auto error =
- hwcLayer->setTransform(static_cast<HWC2::Transform>(mState.bufferTransform));
+ if (auto error = hwcLayer->setSurfaceDamage(outputIndependentState.surfaceDamage);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set surface damage: %s (%d)", mLayerFE->getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ outputIndependentState.surfaceDamage.dump(LOG_TAG);
+ }
+
+ // Content-specific per-frame state
+ switch (outputIndependentState.compositionType) {
+ case Hwc2::IComposerClient::Composition::SOLID_COLOR:
+ writeSolidColorStateToHWC(hwcLayer, outputIndependentState);
+ break;
+ case Hwc2::IComposerClient::Composition::SIDEBAND:
+ writeSidebandStateToHWC(hwcLayer, outputIndependentState);
+ break;
+ case Hwc2::IComposerClient::Composition::CURSOR:
+ case Hwc2::IComposerClient::Composition::DEVICE:
+ writeBufferStateToHWC(hwcLayer, outputIndependentState);
+ break;
+ case Hwc2::IComposerClient::Composition::INVALID:
+ case Hwc2::IComposerClient::Composition::CLIENT:
+ // Ignored
+ break;
+ }
+}
+
+void OutputLayer::writeSolidColorStateToHWC(HWC2::Layer* hwcLayer,
+ const LayerFECompositionState& outputIndependentState) {
+ hwc_color_t color = {static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.r)),
+ static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.g)),
+ static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.b)),
+ 255};
+
+ if (auto error = hwcLayer->setColor(color); error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set color: %s (%d)", mLayerFE->getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeSidebandStateToHWC(HWC2::Layer* hwcLayer,
+ const LayerFECompositionState& outputIndependentState) {
+ if (auto error = hwcLayer->setSidebandStream(outputIndependentState.sidebandStream->handle());
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mLayerFE->getDebugName(),
+ outputIndependentState.sidebandStream->handle(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer,
+ const LayerFECompositionState& outputIndependentState) {
+ auto supportedPerFrameMetadata =
+ mOutput.getDisplayColorProfile()->getSupportedPerFrameMetadata();
+ if (auto error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata,
+ outputIndependentState.hdrMetadata);
+ error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
+ ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mLayerFE->getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ uint32_t hwcSlot = 0;
+ sp<GraphicBuffer> hwcBuffer;
+ // We need access to the output-dependent state for the buffer cache there,
+ // though otherwise the buffer is not output-dependent.
+ editState().hwc->hwcBufferCache.getHwcBuffer(outputIndependentState.bufferSlot,
+ outputIndependentState.buffer, &hwcSlot,
+ &hwcBuffer);
+
+ if (auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, outputIndependentState.acquireFence);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set buffer %p: %s (%d)", mLayerFE->getDebugName(),
+ outputIndependentState.buffer->handle, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeCompositionTypeToHWC(
+ HWC2::Layer* hwcLayer, Hwc2::IComposerClient::Composition requestedCompositionType) {
+ auto& outputDependentState = editState();
+
+ // If we are forcing client composition, we need to tell the HWC
+ if (outputDependentState.forceClientComposition) {
+ requestedCompositionType = Hwc2::IComposerClient::Composition::CLIENT;
+ }
+
+ // Set the requested composition type with the HWC whenever it changes
+ if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType) {
+ outputDependentState.hwc->hwcCompositionType = requestedCompositionType;
+
+ if (auto error = hwcLayer->setCompositionType(
+ static_cast<HWC2::Composition>(requestedCompositionType));
error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set transform %s: %s (%d)", mLayerFE->getDebugName(),
- toString(mState.bufferTransform).c_str(), to_string(error).c_str(),
+ ALOGE("[%s] Failed to set composition type %s: %s (%d)", mLayerFE->getDebugName(),
+ toString(requestedCompositionType).c_str(), to_string(error).c_str(),
static_cast<int32_t>(error));
}
-
- // Output independent state
-
- const auto& outputIndependentState = mLayer->getState().frontEnd;
-
- if (auto error = hwcLayer->setBlendMode(
- static_cast<HWC2::BlendMode>(outputIndependentState.blendMode));
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set blend mode %s: %s (%d)", mLayerFE->getDebugName(),
- toString(outputIndependentState.blendMode).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-
- if (auto error = hwcLayer->setPlaneAlpha(outputIndependentState.alpha);
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set plane alpha %.3f: %s (%d)", mLayerFE->getDebugName(),
- outputIndependentState.alpha, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-
- if (auto error =
- hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId);
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set info %s (%d)", mLayerFE->getDebugName(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index 861ea57..e320bee 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -47,6 +47,7 @@
dumpVal(out, "displayFrame", displayFrame);
dumpVal(out, "sourceCrop", sourceCrop);
dumpVal(out, "bufferTransform", toString(bufferTransform), bufferTransform);
+ dumpVal(out, "dataspace", toString(dataspace), dataspace);
dumpVal(out, "z-index", z);
if (hwc) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index 3766f27..0dbf8f0 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -14,7 +14,11 @@
* limitations under the License.
*/
+#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/impl/CompositionEngine.h>
+#include <compositionengine/mock/Layer.h>
+#include <compositionengine/mock/LayerFE.h>
+#include <compositionengine/mock/Output.h>
#include <gtest/gtest.h>
#include <renderengine/mock/RenderEngine.h>
@@ -23,19 +27,19 @@
namespace android::compositionengine {
namespace {
+using ::testing::_;
+using ::testing::Return;
+using ::testing::SaveArg;
using ::testing::StrictMock;
class CompositionEngineTest : public testing::Test {
public:
- ~CompositionEngineTest() override;
- mock::HWComposer* mHwc = new StrictMock<mock::HWComposer>();
+ android::mock::HWComposer* mHwc = new StrictMock<android::mock::HWComposer>();
renderengine::mock::RenderEngine* mRenderEngine =
new StrictMock<renderengine::mock::RenderEngine>();
impl::CompositionEngine mEngine;
};
-CompositionEngineTest::~CompositionEngineTest() = default;
-
TEST_F(CompositionEngineTest, canInstantiateCompositionEngine) {
auto engine = impl::createCompositionEngine();
EXPECT_TRUE(engine.get() != nullptr);
@@ -53,5 +57,84 @@
EXPECT_EQ(mRenderEngine, &mEngine.getRenderEngine());
}
+/*
+ * CompositionEngine::preComposition
+ */
+
+class PreCompositionTest : public CompositionEngineTest {
+public:
+ PreCompositionTest() {
+ EXPECT_CALL(*mLayer1, getLayerFE()).WillRepeatedly(Return(mLayer1FE));
+ EXPECT_CALL(*mLayer2, getLayerFE()).WillRepeatedly(Return(mLayer2FE));
+ EXPECT_CALL(*mLayer3, getLayerFE()).WillRepeatedly(Return(mLayer3FE));
+ // getLayerFE() can return nullptr. Ensure that this is handled.
+ EXPECT_CALL(*mLayer4, getLayerFE()).WillRepeatedly(Return(nullptr));
+
+ mRefreshArgs.outputs = {mOutput};
+ mRefreshArgs.layers = {mLayer1, mLayer2, mLayer3, mLayer4};
+ }
+
+ std::shared_ptr<mock::Output> mOutput{std::make_shared<StrictMock<mock::Output>>()};
+ std::shared_ptr<mock::Layer> mLayer1{std::make_shared<StrictMock<mock::Layer>>()};
+ std::shared_ptr<mock::Layer> mLayer2{std::make_shared<StrictMock<mock::Layer>>()};
+ std::shared_ptr<mock::Layer> mLayer3{std::make_shared<StrictMock<mock::Layer>>()};
+ std::shared_ptr<mock::Layer> mLayer4{std::make_shared<StrictMock<mock::Layer>>()};
+ sp<StrictMock<mock::LayerFE>> mLayer1FE{new StrictMock<mock::LayerFE>()};
+ sp<StrictMock<mock::LayerFE>> mLayer2FE{new StrictMock<mock::LayerFE>()};
+ sp<StrictMock<mock::LayerFE>> mLayer3FE{new StrictMock<mock::LayerFE>()};
+
+ CompositionRefreshArgs mRefreshArgs;
+};
+
+TEST_F(PreCompositionTest, preCompositionSetsFrameTimestamp) {
+ const nsecs_t before = systemTime(SYSTEM_TIME_MONOTONIC);
+ CompositionRefreshArgs emptyArgs;
+ mEngine.preComposition(emptyArgs);
+ const nsecs_t after = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // The frame timestamp should be between the before and after timestamps
+ EXPECT_GE(mEngine.getLastFrameRefreshTimestamp(), before);
+ EXPECT_LE(mEngine.getLastFrameRefreshTimestamp(), after);
+}
+
+TEST_F(PreCompositionTest, preCompositionInvokesLayerPreCompositionWithFrameTimestamp) {
+ nsecs_t ts1 = 0;
+ nsecs_t ts2 = 0;
+ nsecs_t ts3 = 0;
+ EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts1), Return(false)));
+ EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts2), Return(false)));
+ EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts3), Return(false)));
+
+ mEngine.preComposition(mRefreshArgs);
+
+ // Each of the onPreComposition calls should used the same refresh timestamp
+ EXPECT_EQ(ts1, mEngine.getLastFrameRefreshTimestamp());
+ EXPECT_EQ(ts2, mEngine.getLastFrameRefreshTimestamp());
+ EXPECT_EQ(ts3, mEngine.getLastFrameRefreshTimestamp());
+}
+
+TEST_F(PreCompositionTest, preCompositionDefaultsToNoUpdateNeeded) {
+ EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false));
+
+ mEngine.setNeedsAnotherUpdateForTest(true);
+
+ mEngine.preComposition(mRefreshArgs);
+
+ // The call should have cleared the needsAnotherUpdate flag
+ EXPECT_FALSE(mEngine.needsAnotherUpdate());
+}
+
+TEST_F(PreCompositionTest, preCompositionSetsNeedsAnotherUpdateIfAtLeastOneLayerRequestsIt) {
+ EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false));
+
+ mEngine.preComposition(mRefreshArgs);
+
+ EXPECT_TRUE(mEngine.needsAnotherUpdate());
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
index 9215884..c07dfbb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
@@ -638,5 +638,66 @@
checkGetBestColorMode(profile, expectedResults);
}
+/*
+ * RenderSurface::isDataspaceSupported()
+ */
+
+TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithNoHdrSupport) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_HLG));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG));
+}
+
+TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithHdr10Support) {
+ auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
+
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_PQ));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_HLG));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG));
+}
+
+TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithHlgSupport) {
+ auto profile = ProfileFactory::createProfileWithBT2100PQSupport();
+
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_HLG));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG));
+}
+
+/*
+ * RenderSurface::getTargetDataspace()
+ */
+
+TEST_F(DisplayColorProfileTest, getTargetDataspaceWorks) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ // For a non-HDR colorspace with no colorSpaceAgnosticDataspace override,
+ // the input dataspace should be returned.
+ EXPECT_EQ(Dataspace::DISPLAY_P3,
+ profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3,
+ Dataspace::UNKNOWN));
+
+ // If colorSpaceAgnosticDataspace is set, its value should be returned
+ EXPECT_EQ(Dataspace::V0_SRGB,
+ profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3,
+ Dataspace::V0_SRGB));
+
+ // For an HDR colorspace, Dataspace::UNKNOWN should be returned.
+ EXPECT_EQ(Dataspace::UNKNOWN,
+ profile.getTargetDataspace(ColorMode::BT2100_PQ, Dataspace::BT2020_PQ,
+ Dataspace::UNKNOWN));
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 33444a5..f0aea25 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -22,6 +22,7 @@
#include <compositionengine/RenderSurfaceCreationArgs.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/NativeWindow.h>
#include <compositionengine/mock/RenderSurface.h>
#include <gtest/gtest.h>
@@ -31,6 +32,7 @@
namespace android::compositionengine {
namespace {
+using testing::_;
using testing::Return;
using testing::ReturnRef;
using testing::StrictMock;
@@ -140,21 +142,27 @@
TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) {
mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
mDisplay.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+ mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mDisplay.setDisplayColorProfileForTest(std::unique_ptr<DisplayColorProfile>(colorProfile));
EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+ EXPECT_CALL(*colorProfile, getTargetDataspace(_, _, _))
+ .WillRepeatedly(Return(ui::Dataspace::UNKNOWN));
// These values are expected to be the initial state.
ASSERT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+ ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
- // Otherwise if the values are unchanged, nothing happens
+ // If the set values are unchanged, nothing happens
mDisplay.setColorMode(ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
- ui::RenderIntent::COLORIMETRIC);
+ ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
// Otherwise if the values are different, updates happen
EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
@@ -164,23 +172,34 @@
.Times(1);
mDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mDisplay.getState().colorMode);
EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mDisplay.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay.getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
}
TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) {
impl::Display virtualDisplay{mCompositionEngine,
DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}};
+ mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>();
+ virtualDisplay.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(colorProfile));
+
+ EXPECT_CALL(*colorProfile,
+ getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::Dataspace::UNKNOWN))
+ .WillOnce(Return(ui::Dataspace::UNKNOWN));
+
virtualDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode);
EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay.getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
}
/* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index ae906cd..7b9528b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -16,6 +16,7 @@
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/Layer.h>
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/Output.h>
@@ -25,6 +26,7 @@
#include "MockHWC2.h"
#include "MockHWComposer.h"
#include "RectMatcher.h"
+#include "RegionMatcher.h"
namespace android::compositionengine {
namespace {
@@ -45,6 +47,15 @@
const std::string kOutputName{"Test Output"};
+MATCHER_P(ColorEq, expected, "") {
+ *result_listener << "Colors are not equal\n";
+ *result_listener << "expected " << expected.r << " " << expected.g << " " << expected.b << " "
+ << expected.a << "\n";
+ *result_listener << "actual " << arg.r << " " << arg.g << " " << arg.b << " " << arg.a << "\n";
+
+ return expected.r == arg.r && expected.g == arg.g && expected.b == arg.b && expected.a == arg.a;
+}
+
class OutputLayerTest : public testing::Test {
public:
OutputLayerTest() {
@@ -429,6 +440,9 @@
OutputLayerUpdateCompositionStateTest() {
EXPECT_CALL(*mLayer, getState()).WillRepeatedly(ReturnRef(mLayerState));
EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
+ EXPECT_CALL(mOutput, getDisplayColorProfile())
+ .WillRepeatedly(Return(&mDisplayColorProfile));
+ EXPECT_CALL(mDisplayColorProfile, isDataspaceSupported(_)).WillRepeatedly(Return(true));
}
~OutputLayerUpdateCompositionStateTest() = default;
@@ -453,6 +467,7 @@
using OutputLayer = OutputLayerPartialMockForUpdateCompositionState;
StrictMock<OutputLayer> mOutputLayer{mOutput, mLayer, mLayerFE};
+ StrictMock<mock::DisplayColorProfile> mDisplayColorProfile;
};
TEST_F(OutputLayerUpdateCompositionStateTest, setsStateNormally) {
@@ -498,12 +513,50 @@
EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
}
+TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceCorrectly) {
+ mLayerState.frontEnd.dataspace = ui::Dataspace::DISPLAY_P3;
+ mOutputState.targetDataspace = ui::Dataspace::V0_SCRGB;
+
+ // If the layer is not colorspace agnostic, the output layer dataspace
+ // should use the layers requested colorspace.
+ mLayerState.frontEnd.isColorspaceAgnostic = false;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutputLayer.getState().dataspace);
+
+ // If the layer is colorspace agnostic, the output layer dataspace
+ // should use the colorspace chosen for the whole output.
+ mLayerState.frontEnd.isColorspaceAgnostic = true;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace);
+}
+
TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) {
mOutputLayer.updateCompositionState(false);
EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition);
}
+TEST_F(OutputLayerUpdateCompositionStateTest, clientCompositionForcedFromFrontEndFlagAtAnyTime) {
+ mLayerState.frontEnd.forceClientComposition = true;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+}
+
+TEST_F(OutputLayerUpdateCompositionStateTest,
+ clientCompositionForcedFromUnsupportedDataspaceAtAnyTime) {
+ EXPECT_CALL(mDisplayColorProfile, isDataspaceSupported(_)).WillRepeatedly(Return(false));
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+}
+
/*
* OutputLayer::writeStateToHWC()
*/
@@ -518,8 +571,19 @@
static constexpr float kAlpha = 51.f;
static constexpr uint32_t kType = 61u;
static constexpr uint32_t kAppId = 62u;
+ static constexpr ui::Dataspace kDataspace = static_cast<ui::Dataspace>(71);
+ static constexpr int kSupportedPerFrameMetadata = 101;
+ static constexpr int kExpectedHwcSlot = 0;
+ static const half4 kColor;
static const Rect kDisplayFrame;
+ static const Region kVisibleRegion;
+ static const mat4 kColorTransform;
+ static const Region kSurfaceDamage;
+ static const HdrMetadata kHdrMetadata;
+ static native_handle_t* kSidebandStreamHandle;
+ static const sp<GraphicBuffer> kBuffer;
+ static const sp<Fence> kFence;
OutputLayerWriteStateToHWCTest() {
auto& outputLayerState = mOutputLayer.editState();
@@ -529,13 +593,31 @@
outputLayerState.sourceCrop = kSourceCrop;
outputLayerState.z = kZOrder;
outputLayerState.bufferTransform = static_cast<Hwc2::Transform>(kBufferTransform);
+ outputLayerState.visibleRegion = kVisibleRegion;
+ outputLayerState.dataspace = kDataspace;
mLayerState.frontEnd.blendMode = kBlendMode;
mLayerState.frontEnd.alpha = kAlpha;
mLayerState.frontEnd.type = kType;
mLayerState.frontEnd.appId = kAppId;
+ mLayerState.frontEnd.colorTransform = kColorTransform;
+ mLayerState.frontEnd.color = kColor;
+ mLayerState.frontEnd.surfaceDamage = kSurfaceDamage;
+ mLayerState.frontEnd.hdrMetadata = kHdrMetadata;
+ mLayerState.frontEnd.sidebandStream = NativeHandle::create(kSidebandStreamHandle, false);
+ mLayerState.frontEnd.buffer = kBuffer;
+ mLayerState.frontEnd.bufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
+ mLayerState.frontEnd.acquireFence = kFence;
+
+ EXPECT_CALL(mOutput, getDisplayColorProfile())
+ .WillRepeatedly(Return(&mDisplayColorProfile));
+ EXPECT_CALL(mDisplayColorProfile, getSupportedPerFrameMetadata())
+ .WillRepeatedly(Return(kSupportedPerFrameMetadata));
}
+ // Some tests may need to simulate unsupported HWC calls
+ enum class SimulateUnsupported { None, ColorTransform };
+
void expectGeometryCommonCalls() {
EXPECT_CALL(*mHwcLayer, setDisplayFrame(kDisplayFrame)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setSourceCrop(kSourceCrop)).WillOnce(Return(kError));
@@ -549,10 +631,62 @@
EXPECT_CALL(*mHwcLayer, setInfo(kType, kAppId)).WillOnce(Return(kError));
}
+ void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None) {
+ EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(kVisibleRegion)))
+ .WillOnce(Return(kError));
+ EXPECT_CALL(*mHwcLayer, setDataspace(kDataspace)).WillOnce(Return(kError));
+ EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform))
+ .WillOnce(Return(unsupported == SimulateUnsupported::ColorTransform
+ ? HWC2::Error::Unsupported
+ : HWC2::Error::None));
+ EXPECT_CALL(*mHwcLayer, setSurfaceDamage(RegionEq(kSurfaceDamage)))
+ .WillOnce(Return(kError));
+ }
+
+ void expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition compositionType) {
+ EXPECT_CALL(*mHwcLayer, setCompositionType(static_cast<HWC2::Composition>(compositionType)))
+ .WillOnce(Return(kError));
+ }
+
+ void expectNoSetCompositionTypeCall() {
+ EXPECT_CALL(*mHwcLayer, setCompositionType(_)).Times(0);
+ }
+
+ void expectSetColorCall() {
+ hwc_color_t color = {static_cast<uint8_t>(std::round(kColor.r * 255)),
+ static_cast<uint8_t>(std::round(kColor.g * 255)),
+ static_cast<uint8_t>(std::round(kColor.b * 255)), 255};
+
+ EXPECT_CALL(*mHwcLayer, setColor(ColorEq(color))).WillOnce(Return(kError));
+ }
+
+ void expectSetSidebandHandleCall() {
+ EXPECT_CALL(*mHwcLayer, setSidebandStream(kSidebandStreamHandle));
+ }
+
+ void expectSetHdrMetadataAndBufferCalls() {
+ EXPECT_CALL(*mHwcLayer, setPerFrameMetadata(kSupportedPerFrameMetadata, kHdrMetadata));
+ EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, kBuffer, kFence));
+ }
+
std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()};
+ StrictMock<mock::DisplayColorProfile> mDisplayColorProfile;
};
+const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 83.f / 255.f,
+ 84.f / 255.f};
const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
+const Region OutputLayerWriteStateToHWCTest::kVisibleRegion{Rect{1005, 1006, 1007, 1008}};
+const mat4 OutputLayerWriteStateToHWCTest::kColorTransform{
+ 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016,
+ 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024,
+};
+const Region OutputLayerWriteStateToHWCTest::kSurfaceDamage{Rect{1025, 1026, 1027, 1028}};
+const HdrMetadata OutputLayerWriteStateToHWCTest::kHdrMetadata{{/* LightFlattenable */}, 1029};
+native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle =
+ reinterpret_cast<native_handle_t*>(1031);
+const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer;
+const sp<Fence> OutputLayerWriteStateToHWCTest::kFence;
TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCState) {
mOutputLayer.editState().hwc.reset();
@@ -566,11 +700,89 @@
mOutputLayer.writeStateToHWC(true);
}
-TEST_F(OutputLayerWriteStateToHWCTest, canSetsAllState) {
+TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) {
expectGeometryCommonCalls();
+ expectPerFrameCommonCalls();
+
+ expectNoSetCompositionTypeCall();
mOutputLayer.writeStateToHWC(true);
}
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls();
+ expectSetColorCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SOLID_COLOR);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
+
+ expectPerFrameCommonCalls();
+ expectSetSidebandHandleCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SIDEBAND);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::CURSOR;
+
+ expectPerFrameCommonCalls();
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CURSOR);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ expectPerFrameCommonCalls();
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) {
+ (*mOutputLayer.editState().hwc).hwcCompositionType =
+ Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls();
+ expectSetColorCall();
+ expectNoSetCompositionTypeCall();
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransformNotSupported) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls(SimulateUnsupported::ColorTransform);
+ expectSetColorCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompositionForced) {
+ mOutputLayer.editState().forceClientComposition = true;
+
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls();
+ expectSetColorCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index fee0c11..6f087d9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -205,24 +205,36 @@
*/
TEST_F(OutputTest, setColorModeSetsStateAndDirtiesOutputIfChanged) {
+ EXPECT_CALL(*mDisplayColorProfile,
+ getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::Dataspace::UNKNOWN))
+ .WillOnce(Return(ui::Dataspace::UNKNOWN));
EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput.getState().colorMode);
EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput.getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mOutput.getState().targetDataspace);
+
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) {
+ EXPECT_CALL(*mDisplayColorProfile,
+ getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::Dataspace::UNKNOWN))
+ .WillOnce(Return(ui::Dataspace::UNKNOWN));
+
mOutput.editState().colorMode = ui::ColorMode::DISPLAY_P3;
mOutput.editState().dataspace = ui::Dataspace::DISPLAY_P3;
mOutput.editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC;
+ mOutput.editState().targetDataspace = ui::Dataspace::UNKNOWN;
mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
}
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 7927fa9..3a5f3fa 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -39,7 +39,4 @@
return !isHiddenByPolicy();
}
-void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
- const Rect&, int32_t, const ui::Dataspace) {}
-
} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 7222a3e..57267c7 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -33,10 +33,6 @@
bool canReceiveInput() const override;
- void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) override;
-
bool isCreatedFromMainThread() const override { return true; }
bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 4a13bfb..d136562 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -126,14 +126,6 @@
return mVisibleLayersSortedByZ;
}
-void DisplayDevice::setLayersNeedingFences(const Vector< sp<Layer> >& layers) {
- mLayersNeedingFences = layers;
-}
-
-const Vector< sp<Layer> >& DisplayDevice::getLayersNeedingFences() const {
- return mLayersNeedingFences;
-}
-
// ----------------------------------------------------------------------------
void DisplayDevice::setPowerMode(int mode) {
mPowerMode = mode;
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 0067b50..8bc19d4 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -88,8 +88,6 @@
void setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
- void setLayersNeedingFences(const Vector< sp<Layer> >& layers);
- const Vector< sp<Layer> >& getLayersNeedingFences() const;
void setLayerStack(uint32_t stack);
void setDisplaySize(const int newWidth, const int newHeight);
@@ -182,8 +180,6 @@
// list of visible layers on that display
Vector< sp<Layer> > mVisibleLayersSortedByZ;
- // list of layers needing fences
- Vector< sp<Layer> > mLayersNeedingFences;
/*
* Transaction state
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 26c61ba..b5f0800 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -242,20 +242,6 @@
// h/w composer set-up
// ---------------------------------------------------------------------------
-bool Layer::hasHwcLayer(const sp<const DisplayDevice>& displayDevice) {
- auto outputLayer = findOutputLayerForDisplay(displayDevice);
- LOG_FATAL_IF(!outputLayer);
- return outputLayer->getState().hwc && (*outputLayer->getState().hwc).hwcLayer != nullptr;
-}
-
-HWC2::Layer* Layer::getHwcLayer(const sp<const DisplayDevice>& displayDevice) {
- auto outputLayer = findOutputLayerForDisplay(displayDevice);
- if (!outputLayer || !outputLayer->getState().hwc) {
- return nullptr;
- }
- return (*outputLayer->getState().hwc).hwcLayer.get();
-}
-
Rect Layer::getContentCrop() const {
// this is the crop rectangle that applies to the buffer
// itself (as opposed to the window)
@@ -454,29 +440,38 @@
compositionState.appId = appId;
}
+void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compositionState) const {
+ compositionState.forceClientComposition = false;
+
+ // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
+ // value recomputed / set every frame.
+ compositionState.geomVisibleRegion = visibleRegion;
+
+ compositionState.isColorspaceAgnostic = isColorSpaceAgnostic();
+ compositionState.dataspace = mCurrentDataSpace;
+ compositionState.colorTransform = getColorTransform();
+ compositionState.colorTransformIsIdentity = !hasColorTransform();
+ compositionState.surfaceDamage = surfaceDamageRegion;
+
+ // Force client composition for special cases known only to the front-end.
+ if (isHdrY410() || getRoundedCornerState().radius > 0.0f) {
+ compositionState.forceClientComposition = true;
+ }
+}
+
void Layer::latchCompositionState(compositionengine::LayerFECompositionState& compositionState,
bool includeGeometry) const {
if (includeGeometry) {
latchGeometry(compositionState);
}
+
+ latchPerFrameState(compositionState);
}
const char* Layer::getDebugName() const {
return mName.string();
}
-void Layer::forceClientComposition(const sp<DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- outputLayer->editState().forceClientComposition = true;
-}
-
-bool Layer::getForceClientComposition(const sp<DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- return outputLayer->getState().forceClientComposition;
-}
-
void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
const auto outputLayer = findOutputLayerForDisplay(display);
LOG_FATAL_IF(!outputLayer);
@@ -563,29 +558,6 @@
return true;
}
-void Layer::setCompositionType(const sp<const DisplayDevice>& display,
- Hwc2::IComposerClient::Composition type) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- LOG_FATAL_IF(!outputLayer->getState().hwc);
- auto& compositionState = outputLayer->editState();
-
- ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", ((*compositionState.hwc).hwcLayer)->getId(),
- toString(type).c_str(), 1);
- if ((*compositionState.hwc).hwcCompositionType != type) {
- ALOGV(" actually setting");
- (*compositionState.hwc).hwcCompositionType = type;
-
- auto error = (*compositionState.hwc)
- .hwcLayer->setCompositionType(static_cast<HWC2::Composition>(type));
- ALOGE_IF(error != HWC2::Error::None,
- "[%s] Failed to set "
- "composition type %s: %s (%d)",
- mName.string(), toString(type).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-}
-
Hwc2::IComposerClient::Composition Layer::getCompositionType(
const sp<const DisplayDevice>& display) const {
const auto outputLayer = findOutputLayerForDisplay(display);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b693a47..45199dd 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -469,23 +469,13 @@
protected:
void latchGeometry(compositionengine::LayerFECompositionState& outState) const;
+ virtual void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const;
public:
virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
virtual bool isHdrY410() const { return false; }
- void forceClientComposition(const sp<DisplayDevice>& display);
- bool getForceClientComposition(const sp<DisplayDevice>& display);
- virtual void setPerFrameData(const sp<const DisplayDevice>& display,
- const ui::Transform& transform, const Rect& viewport,
- int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) = 0;
-
- // callIntoHwc exists so we can update our local state and call
- // acceptDisplayChanges without unnecessarily updating the device's state
- void setCompositionType(const sp<const DisplayDevice>& display,
- Hwc2::IComposerClient::Composition type);
Hwc2::IComposerClient::Composition getCompositionType(
const sp<const DisplayDevice>& display) const;
bool getClearClientTarget(const sp<const DisplayDevice>& display) const;
@@ -495,12 +485,6 @@
virtual void setTransformHint(uint32_t /*orientation*/) const { }
/*
- * called before composition.
- * returns true if the layer has pending updates.
- */
- virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
-
- /*
* called after composition.
* returns true if the layer latched a new buffer this frame.
*/
@@ -561,8 +545,9 @@
* operation, so this should be set only if needed). Typically this is used
* to figure out if the content or size of a surface has changed.
*/
- virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/) {
- return {};
+ virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
+ nsecs_t /*expectedPresentTime*/) {
+ return false;
}
virtual bool isBufferLatched() const { return false; }
@@ -607,10 +592,6 @@
virtual int32_t getQueuedFrameCount() const { return 0; }
// -----------------------------------------------------------------------
-
- bool hasHwcLayer(const sp<const DisplayDevice>& displayDevice);
- HWC2::Layer* getHwcLayer(const sp<const DisplayDevice>& displayDevice);
-
inline const State& getDrawingState() const { return mDrawingState; }
inline const State& getCurrentState() const { return mCurrentState; }
inline State& getCurrentState() { return mCurrentState; }
@@ -812,7 +793,7 @@
// this to be called once.
sp<IBinder> getHandle();
const String8& getName() const;
- virtual void notifyAvailableFrames() {}
+ virtual void notifyAvailableFrames(nsecs_t /*expectedPresentTime*/) {}
virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
bool getPremultipledAlpha() const;
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 0c94052..ad5eb33 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -64,7 +64,7 @@
DispSyncThread(const char* name, bool showTraceDetailedInfo)
: mName(name),
mStop(false),
- mModelLocked(false),
+ mModelLocked("DispSync:ModelLocked", false),
mPeriod(0),
mPhase(0),
mReferenceTime(0),
@@ -121,13 +121,11 @@
void lockModel() {
Mutex::Autolock lock(mMutex);
mModelLocked = true;
- ATRACE_INT("DispSync:ModelLocked", mModelLocked);
}
void unlockModel() {
Mutex::Autolock lock(mMutex);
mModelLocked = false;
- ATRACE_INT("DispSync:ModelLocked", mModelLocked);
}
virtual bool threadLoop() {
@@ -431,7 +429,7 @@
const char* const mName;
bool mStop;
- bool mModelLocked;
+ TracedOrdinal<bool> mModelLocked;
nsecs_t mPeriod;
nsecs_t mPhase;
@@ -454,15 +452,14 @@
class ZeroPhaseTracer : public DispSync::Callback {
public:
- ZeroPhaseTracer() : mParity(false) {}
+ ZeroPhaseTracer() : mParity("ZERO_PHASE_VSYNC", false) {}
virtual void onDispSyncEvent(nsecs_t /*when*/) {
mParity = !mParity;
- ATRACE_INT("ZERO_PHASE_VSYNC", mParity ? 1 : 0);
}
private:
- bool mParity;
+ TracedOrdinal<bool> mParity;
};
DispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0) {
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 5faf46e..571c9ca 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -31,19 +31,16 @@
nsecs_t offsetThresholdForNextVsync, bool traceVsync,
const char* name)
: mName(name),
+ mValue(base::StringPrintf("VSYNC-%s", name), 0),
mTraceVsync(traceVsync),
mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
- mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)),
- mVsyncOffsetLabel(base::StringPrintf("VsyncOffset-%s", name)),
- mVsyncNegativeOffsetLabel(base::StringPrintf("VsyncNegativeOffset-%s", name)),
mDispSync(dispSync),
- mPhaseOffset(phaseOffset),
+ mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset),
mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {}
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
if (enable) {
- tracePhaseOffset();
status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
static_cast<DispSync::Callback*>(this),
mLastCallbackTime);
@@ -83,7 +80,6 @@
}
mPhaseOffset = phaseOffset;
- tracePhaseOffset();
// If we're not enabled, we don't need to mess with the listeners
if (!mEnabled) {
@@ -106,7 +102,6 @@
if (mTraceVsync) {
mValue = (mValue + 1) % 2;
- ATRACE_INT(mVsyncEventLabel.c_str(), mValue);
}
if (callback != nullptr) {
@@ -114,14 +109,4 @@
}
}
-void DispSyncSource::tracePhaseOffset() {
- if (mPhaseOffset > 0) {
- ATRACE_INT(mVsyncOffsetLabel.c_str(), mPhaseOffset);
- ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), 0);
- } else {
- ATRACE_INT(mVsyncOffsetLabel.c_str(), 0);
- ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), -mPhaseOffset);
- }
-}
-
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 50560a5..740c8c4 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -20,6 +20,7 @@
#include "DispSync.h"
#include "EventThread.h"
+#include "TracedOrdinal.h"
namespace android {
@@ -39,16 +40,11 @@
// The following method is the implementation of the DispSync::Callback.
virtual void onDispSyncEvent(nsecs_t when);
- void tracePhaseOffset() REQUIRES(mVsyncMutex);
-
const char* const mName;
- int mValue = 0;
+ TracedOrdinal<int> mValue;
const bool mTraceVsync;
const std::string mVsyncOnLabel;
- const std::string mVsyncEventLabel;
- const std::string mVsyncOffsetLabel;
- const std::string mVsyncNegativeOffsetLabel;
nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0;
DispSync* mDispSync;
@@ -57,7 +53,7 @@
VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr;
std::mutex mVsyncMutex;
- nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex);
+ TracedOrdinal<nsecs_t> mPhaseOffset GUARDED_BY(mVsyncMutex);
const nsecs_t mOffsetThresholdForNextVsync;
bool mEnabled GUARDED_BY(mVsyncMutex) = false;
};
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 8a2604f..9f8567d 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -18,115 +18,102 @@
#include <cutils/properties.h>
+#include <optional>
+
#include "SurfaceFlingerProperties.h"
-namespace android {
-using namespace android::sysprop;
+namespace {
-namespace scheduler {
+std::optional<int> getProperty(const char* name) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get(name, value, "-1");
+ if (const int i = atoi(value); i != -1) return i;
+ return std::nullopt;
+}
-using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+} // namespace
+
+namespace android::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, "2000000");
- const int highFpsLateAppOffsetNs = atoi(value);
-
- property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "1000000");
- const int highFpsLateSfOffsetNs = atoi(value);
-
// Below defines the threshold when an offset is considered to be negative, i.e. targeting
// for the N+2 vsync instead of N+1. This means that:
// For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync.
// For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync.
- property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1");
- const int phaseOffsetThresholdForNextVsyncNs = atoi(value);
+ const nsecs_t thresholdForNextVsync =
+ getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
+ .value_or(std::numeric_limits<nsecs_t>::max());
- Offsets defaultOffsets;
- Offsets highFpsOffsets;
- defaultOffsets.early = {RefreshRateType::DEFAULT,
- earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
- earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
- defaultOffsets.earlyGl = {RefreshRateType::DEFAULT,
- earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
- earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
- defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
-
- highFpsOffsets.early = {RefreshRateType::PERFORMANCE,
- highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
- : highFpsLateSfOffsetNs,
- highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
- : highFpsLateAppOffsetNs};
- highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE,
- highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
- : highFpsLateSfOffsetNs,
- highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
- : highFpsLateAppOffsetNs};
- highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs,
- highFpsLateAppOffsetNs};
+ const Offsets defaultOffsets = getDefaultOffsets(thresholdForNextVsync);
+ const Offsets highFpsOffsets = getHighFpsOffsets(thresholdForNextVsync);
mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets});
mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets});
mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets});
-
- mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1
- ? phaseOffsetThresholdForNextVsyncNs
- : std::numeric_limits<nsecs_t>::max();
}
PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(
- android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const {
+ RefreshRateType refreshRateType) const {
return mOffsets.at(refreshRateType);
}
void PhaseOffsets::dump(std::string& result) const {
- const auto [early, earlyGl, late] = getCurrentOffsets();
+ const auto [early, earlyGl, late, threshold] = 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);
+ "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
+ "threshold for next VSYNC: %" PRId64 " ns\n",
+ late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf, threshold);
}
-nsecs_t PhaseOffsets::getCurrentAppOffset() {
- return getCurrentOffsets().late.app;
+PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t thresholdForNextVsync) {
+ const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000);
+ const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000);
+
+ const auto earlySfOffsetNs = getProperty("debug.sf.early_phase_offset_ns");
+ const auto earlyGlSfOffsetNs = getProperty("debug.sf.early_gl_phase_offset_ns");
+ const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns");
+ const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns");
+
+ return {{RefreshRateType::DEFAULT, earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs),
+ earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs)},
+
+ {RefreshRateType::DEFAULT, earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs),
+ earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs)},
+
+ {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs},
+
+ thresholdForNextVsync};
}
-nsecs_t PhaseOffsets::getCurrentSfOffset() {
- return getCurrentOffsets().late.sf;
+PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t thresholdForNextVsync) {
+ // TODO(b/122905996): Define these in device.mk.
+ const int highFpsLateAppOffsetNs =
+ getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000);
+ const int highFpsLateSfOffsetNs =
+ getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000);
+
+ const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns");
+ const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
+ const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns");
+ const auto highFpsEarlyGlAppOffsetNs =
+ getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
+
+ return {{RefreshRateType::PERFORMANCE, highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs),
+ highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs)},
+
+ {RefreshRateType::PERFORMANCE, highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs),
+ highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs)},
+
+ {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, highFpsLateAppOffsetNs},
+
+ thresholdForNextVsync};
}
} // namespace impl
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index 2b5c2f1..2c52432 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -16,14 +16,12 @@
#pragma once
-#include <cinttypes>
#include <unordered_map>
#include "RefreshRateConfigs.h"
#include "VSyncModulator.h"
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
/*
* This class encapsulates offsets for different refresh rates. Depending
@@ -33,35 +31,33 @@
*/
class PhaseOffsets {
public:
- struct Offsets {
- VSyncModulator::Offsets early;
- VSyncModulator::Offsets earlyGl;
- VSyncModulator::Offsets late;
- };
+ using Offsets = VSyncModulator::OffsetsConfig;
+ using RefreshRateType = RefreshRateConfigs::RefreshRateType;
virtual ~PhaseOffsets();
- virtual nsecs_t getCurrentAppOffset() = 0;
- virtual nsecs_t getCurrentSfOffset() = 0;
- virtual Offsets getOffsetsForRefreshRate(
- RefreshRateConfigs::RefreshRateType refreshRateType) const = 0;
+ nsecs_t getCurrentAppOffset() const { return getCurrentOffsets().late.app; }
+ nsecs_t getCurrentSfOffset() const { return getCurrentOffsets().late.sf; }
+ nsecs_t getOffsetThresholdForNextVsync() const {
+ return getCurrentOffsets().thresholdForNextVsync;
+ }
+
virtual Offsets getCurrentOffsets() const = 0;
- virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0;
- virtual nsecs_t getOffsetThresholdForNextVsync() const = 0;
+ virtual Offsets getOffsetsForRefreshRate(RefreshRateType) const = 0;
+
+ virtual void setRefreshRateType(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 for a given refresh rate.
- Offsets getOffsetsForRefreshRate(
- RefreshRateConfigs::RefreshRateType refreshRateType) const override;
+ Offsets getOffsetsForRefreshRate(RefreshRateType) const override;
// Returns early, early GL, and late offsets for Apps and SF.
Offsets getCurrentOffsets() const override {
@@ -70,23 +66,21 @@
// 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 {
+ void setRefreshRateType(RefreshRateType refreshRateType) override {
mRefreshRateType = refreshRateType;
}
- nsecs_t getOffsetThresholdForNextVsync() const override { return mOffsetThresholdForNextVsync; }
-
// Returns current offsets in human friendly format.
void dump(std::string& result) const override;
private:
- std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType =
- RefreshRateConfigs::RefreshRateType::DEFAULT;
+ static Offsets getDefaultOffsets(nsecs_t thresholdForNextVsync);
+ static Offsets getHighFpsOffsets(nsecs_t thresholdForNextVsync);
- std::unordered_map<RefreshRateConfigs::RefreshRateType, Offsets> mOffsets;
- nsecs_t mOffsetThresholdForNextVsync;
+ std::atomic<RefreshRateType> mRefreshRateType = RefreshRateType::DEFAULT;
+
+ std::unordered_map<RefreshRateType, Offsets> mOffsets;
};
-} // namespace impl
-} // namespace scheduler
-} // namespace android
+} // namespace impl
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 7acb470..952643c 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -89,12 +89,13 @@
if (mSupportKernelTimer) {
mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
std::chrono::milliseconds(mSetIdleTimerMs),
- [this] { resetKernelTimerCallback(); },
- [this] { expiredKernelTimerCallback(); });
+ [this] { kernelIdleTimerCallback(TimerState::Reset); },
+ [this] { kernelIdleTimerCallback(TimerState::Expired); });
} else {
mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
- std::chrono::milliseconds(mSetIdleTimerMs), [this] { resetTimerCallback(); },
- [this] { expiredTimerCallback(); });
+ std::chrono::milliseconds(mSetIdleTimerMs),
+ [this] { idleTimerCallback(TimerState::Reset); },
+ [this] { idleTimerCallback(TimerState::Expired); });
}
mIdleTimer->start();
}
@@ -102,16 +103,17 @@
if (mSetTouchTimerMs > 0) {
// Touch events are coming to SF every 100ms, so the timer needs to be higher than that
mTouchTimer = std::make_unique<scheduler::OneShotTimer>(
- std::chrono::milliseconds(mSetTouchTimerMs), [this] { resetTouchTimerCallback(); },
- [this] { expiredTouchTimerCallback(); });
+ std::chrono::milliseconds(mSetTouchTimerMs),
+ [this] { touchTimerCallback(TimerState::Reset); },
+ [this] { touchTimerCallback(TimerState::Expired); });
mTouchTimer->start();
}
if (mSetDisplayPowerTimerMs > 0) {
mDisplayPowerTimer = std::make_unique<scheduler::OneShotTimer>(
std::chrono::milliseconds(mSetDisplayPowerTimerMs),
- [this] { resetDisplayPowerTimerCallback(); },
- [this] { expiredDisplayPowerTimerCallback(); });
+ [this] { displayPowerTimerCallback(TimerState::Reset); },
+ [this] { displayPowerTimerCallback(TimerState::Expired); });
mDisplayPowerTimer->start();
}
}
@@ -363,23 +365,22 @@
RefreshRateType newRefreshRateType;
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
- if (mContentRefreshRate == refreshRateRound && mIsHDRContent == isHDR) {
+ if (mFeatures.contentRefreshRate == refreshRateRound && mFeatures.isHDRContent == isHDR) {
return;
}
- mContentRefreshRate = refreshRateRound;
- ATRACE_INT("ContentFPS", mContentRefreshRate);
+ mFeatures.contentRefreshRate = refreshRateRound;
+ ATRACE_INT("ContentFPS", refreshRateRound);
- mIsHDRContent = isHDR;
- ATRACE_INT("ContentHDR", mIsHDRContent);
+ mFeatures.isHDRContent = isHDR;
+ ATRACE_INT("ContentHDR", isHDR);
- mCurrentContentFeatureState = refreshRateRound > 0
- ? ContentFeatureState::CONTENT_DETECTION_ON
- : ContentFeatureState::CONTENT_DETECTION_OFF;
+ mFeatures.contentDetection =
+ refreshRateRound > 0 ? ContentDetectionState::On : ContentDetectionState::Off;
newRefreshRateType = calculateRefreshRateType();
- if (mRefreshRateType == newRefreshRateType) {
+ if (mFeatures.refreshRateType == newRefreshRateType) {
return;
}
- mRefreshRateType = newRefreshRateType;
+ mFeatures.refreshRateType = newRefreshRateType;
}
changeRefreshRate(newRefreshRateType, ConfigEvent::Changed);
}
@@ -433,7 +434,7 @@
void Scheduler::setDisplayPowerState(bool normal) {
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
- mIsDisplayPowerStateNormal = normal;
+ mFeatures.isDisplayPowerStateNormal = normal;
}
if (mDisplayPowerTimer) {
@@ -445,60 +446,41 @@
mLayerHistory.clearHistory();
}
-void Scheduler::resetTimerCallback() {
- handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::RESET, false);
- ATRACE_INT("ExpiredIdleTimer", 0);
-}
+void Scheduler::kernelIdleTimerCallback(TimerState state) {
+ ATRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state));
-void Scheduler::resetKernelTimerCallback() {
- ATRACE_INT("ExpiredKernelIdleTimer", 0);
std::lock_guard<std::mutex> lock(mCallbackLock);
- if (mGetVsyncPeriod && mGetCurrentRefreshRateTypeCallback) {
+ if (!mGetCurrentRefreshRateTypeCallback || !mGetVsyncPeriod) return;
+
+ const auto type = mGetCurrentRefreshRateTypeCallback();
+ if (state == TimerState::Reset && type == RefreshRateType::PERFORMANCE) {
// If we're not in performance mode then the kernel timer shouldn't do
// anything, as the refresh rate during DPU power collapse will be the
// same.
- if (mGetCurrentRefreshRateTypeCallback() == Scheduler::RefreshRateType::PERFORMANCE) {
- resyncToHardwareVsync(true, mGetVsyncPeriod());
- }
+ resyncToHardwareVsync(true /* makeAvailable */, mGetVsyncPeriod());
+ } else if (state == TimerState::Expired && type != RefreshRateType::PERFORMANCE) {
+ // Disable HW VSYNC if the timer expired, as we don't need it enabled if
+ // we're not pushing frames, and if we're in PERFORMANCE mode then we'll
+ // need to update the DispSync model anyway.
+ disableHardwareVsync(false /* makeUnavailable */);
}
}
-void Scheduler::expiredTimerCallback() {
- handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::EXPIRED, false);
- ATRACE_INT("ExpiredIdleTimer", 1);
+void Scheduler::idleTimerCallback(TimerState state) {
+ handleTimerStateChanged(&mFeatures.idleTimer, state, false /* eventOnContentDetection */);
+ ATRACE_INT("ExpiredIdleTimer", static_cast<int>(state));
}
-void Scheduler::resetTouchTimerCallback() {
- handleTimerStateChanged(&mCurrentTouchState, TouchState::ACTIVE, true);
- ATRACE_INT("TouchState", 1);
+void Scheduler::touchTimerCallback(TimerState state) {
+ const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
+ handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */);
+ ATRACE_INT("TouchState", static_cast<int>(touch));
}
-void Scheduler::expiredTouchTimerCallback() {
- handleTimerStateChanged(&mCurrentTouchState, TouchState::INACTIVE, true);
- ATRACE_INT("TouchState", 0);
-}
-
-void Scheduler::resetDisplayPowerTimerCallback() {
- handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::RESET, true);
- ATRACE_INT("ExpiredDisplayPowerTimer", 0);
-}
-
-void Scheduler::expiredDisplayPowerTimerCallback() {
- handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::EXPIRED, true);
- ATRACE_INT("ExpiredDisplayPowerTimer", 1);
-}
-
-void Scheduler::expiredKernelTimerCallback() {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- ATRACE_INT("ExpiredKernelIdleTimer", 1);
- if (mGetCurrentRefreshRateTypeCallback) {
- if (mGetCurrentRefreshRateTypeCallback() != Scheduler::RefreshRateType::PERFORMANCE) {
- // Disable HW Vsync if the timer expired, as we don't need it
- // enabled if we're not pushing frames, and if we're in PERFORMANCE
- // mode then we'll need to re-update the DispSync model anyways.
- disableHardwareVsync(false);
- }
- }
+void Scheduler::displayPowerTimerCallback(TimerState state) {
+ handleTimerStateChanged(&mFeatures.displayPowerTimer, state,
+ true /* eventOnContentDetection */);
+ ATRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state));
}
std::string Scheduler::doDump() {
@@ -519,12 +501,11 @@
}
*currentState = newState;
newRefreshRateType = calculateRefreshRateType();
- if (mRefreshRateType == newRefreshRateType) {
+ if (mFeatures.refreshRateType == newRefreshRateType) {
return;
}
- mRefreshRateType = newRefreshRateType;
- if (eventOnContentDetection &&
- mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) {
+ mFeatures.refreshRateType = newRefreshRateType;
+ if (eventOnContentDetection && mFeatures.contentDetection == ContentDetectionState::On) {
event = ConfigEvent::Changed;
}
}
@@ -533,37 +514,38 @@
Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
// HDR content is not supported on PERFORMANCE mode
- if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) {
+ if (mForceHDRContentToDefaultRefreshRate && mFeatures.isHDRContent) {
return RefreshRateType::DEFAULT;
}
// If Display Power is not in normal operation we want to be in performance mode.
// When coming back to normal mode, a grace period is given with DisplayPowerTimer
- if (!mIsDisplayPowerStateNormal || mDisplayPowerTimerState == DisplayPowerTimerState::RESET) {
+ if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) {
return RefreshRateType::PERFORMANCE;
}
// As long as touch is active we want to be in performance mode
- if (mCurrentTouchState == TouchState::ACTIVE) {
+ if (mFeatures.touch == TouchState::Active) {
return RefreshRateType::PERFORMANCE;
}
// If timer has expired as it means there is no new content on the screen
- if (mCurrentIdleTimerState == IdleTimerState::EXPIRED) {
+ if (mFeatures.idleTimer == TimerState::Expired) {
return RefreshRateType::DEFAULT;
}
// If content detection is off we choose performance as we don't know the content fps
- if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_OFF) {
+ if (mFeatures.contentDetection == ContentDetectionState::Off) {
return RefreshRateType::PERFORMANCE;
}
// Content detection is on, find the appropriate refresh rate with minimal error
+ const float rate = static_cast<float>(mFeatures.contentRefreshRate);
auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(),
mRefreshRateConfigs.getRefreshRates().cend(),
- [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool {
- return std::abs(l.second->fps - static_cast<float>(rate)) <
- std::abs(r.second->fps - static_cast<float>(rate));
+ [rate](const auto& lhs, const auto& rhs) -> bool {
+ return std::abs(lhs.second->fps - rate) <
+ std::abs(rhs.second->fps - rate);
});
RefreshRateType currRefreshRateType = iter->first;
@@ -571,11 +553,10 @@
// 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
// align well with both
constexpr float MARGIN = 0.05f;
- float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps /
- float(mContentRefreshRate);
+ float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / rate;
if (std::abs(std::round(ratio) - ratio) > MARGIN) {
while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
- ratio = iter->second->fps / float(mContentRefreshRate);
+ ratio = iter->second->fps / rate;
if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
currRefreshRateType = iter->first;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 123036e..0d9d7aa 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -200,10 +200,9 @@
// In order to make sure that the features don't override themselves, we need a state machine
// to keep track which feature requested the config change.
- enum class ContentFeatureState { CONTENT_DETECTION_ON, CONTENT_DETECTION_OFF };
- enum class IdleTimerState { EXPIRED, RESET };
- enum class TouchState { INACTIVE, ACTIVE };
- enum class DisplayPowerTimerState { EXPIRED, RESET };
+ enum class ContentDetectionState { Off, On };
+ enum class TimerState { Reset, Expired };
+ enum class TouchState { Inactive, Active };
// Creates a connection on the given EventThread and forwards the given callbacks.
sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&,
@@ -212,26 +211,12 @@
nsecs_t calculateAverage() const;
void updateFrameSkipping(const int64_t skipCount);
- // Function that is called when the timer resets.
- void resetTimerCallback();
- // Function that is called when the timer expires.
- void expiredTimerCallback();
- // Function that is called when the timer resets when paired with a display
- // driver timeout in the kernel. This enables hardware vsync when we move
- // out from idle.
- void resetKernelTimerCallback();
- // Function that is called when the timer expires when paired with a display
- // driver timeout in the kernel. This disables hardware vsync when we move
- // into idle.
- void expiredKernelTimerCallback();
- // Function that is called when the touch timer resets.
- void resetTouchTimerCallback();
- // Function that is called when the touch timer expires.
- void expiredTouchTimerCallback();
- // Function that is called when the display power timer resets.
- void resetDisplayPowerTimerCallback();
- // Function that is called when the display power timer expires.
- void expiredDisplayPowerTimerCallback();
+ // Update feature state machine to given state when corresponding timer resets or expires.
+ void kernelIdleTimerCallback(TimerState);
+ void idleTimerCallback(TimerState);
+ void touchTimerCallback(TimerState);
+ void displayPowerTimerCallback(TimerState);
+
// Sets vsync period.
void setVsyncPeriod(const nsecs_t period);
// handles various timer features to change the refresh rate.
@@ -304,16 +289,19 @@
// In order to make sure that the features don't override themselves, we need a state machine
// to keep track which feature requested the config change.
std::mutex mFeatureStateLock;
- ContentFeatureState mCurrentContentFeatureState GUARDED_BY(mFeatureStateLock) =
- ContentFeatureState::CONTENT_DETECTION_OFF;
- IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET;
- TouchState mCurrentTouchState GUARDED_BY(mFeatureStateLock) = TouchState::INACTIVE;
- DisplayPowerTimerState mDisplayPowerTimerState GUARDED_BY(mFeatureStateLock) =
- DisplayPowerTimerState::EXPIRED;
- uint32_t mContentRefreshRate GUARDED_BY(mFeatureStateLock);
- RefreshRateType mRefreshRateType GUARDED_BY(mFeatureStateLock);
- bool mIsHDRContent GUARDED_BY(mFeatureStateLock) = false;
- bool mIsDisplayPowerStateNormal GUARDED_BY(mFeatureStateLock) = true;
+
+ struct {
+ ContentDetectionState contentDetection = ContentDetectionState::Off;
+ TimerState idleTimer = TimerState::Reset;
+ TouchState touch = TouchState::Inactive;
+ TimerState displayPowerTimer = TimerState::Expired;
+
+ RefreshRateType refreshRateType = RefreshRateType::DEFAULT;
+ uint32_t contentRefreshRate = 0;
+
+ bool isHDRContent = false;
+ bool isDisplayPowerStateNormal = true;
+ } mFeatures GUARDED_BY(mFeatureStateLock);
const scheduler::RefreshRateConfigs& mRefreshRateConfigs;
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
index 7a3bf8e..f267c99 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
@@ -24,25 +24,24 @@
#include <cinttypes>
#include <mutex>
-namespace android {
+namespace android::scheduler {
-using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
-VSyncModulator::VSyncModulator() {
+VSyncModulator::VSyncModulator(Scheduler& scheduler,
+ const sp<Scheduler::ConnectionHandle>& appConnectionHandle,
+ const sp<Scheduler::ConnectionHandle>& sfConnectionHandle,
+ const OffsetsConfig& config)
+ : mScheduler(scheduler),
+ mAppConnectionHandle(appConnectionHandle),
+ mSfConnectionHandle(sfConnectionHandle),
+ mOffsetsConfig(config) {
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.vsync_trace_detailed_info", value, "0");
mTraceDetailedInfo = atoi(value);
- // Populate the offset map with some default offsets.
- const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0};
- setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0);
}
-void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
- nsecs_t thresholdForNextVsync) {
+void VSyncModulator::setPhaseOffsets(const OffsetsConfig& config) {
std::lock_guard<std::mutex> lock(mMutex);
- mOffsetMap.insert_or_assign(OffsetType::Early, early);
- mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl);
- mOffsetMap.insert_or_assign(OffsetType::Late, late);
- mThresholdForNextVsync = thresholdForNextVsync;
+ mOffsetsConfig = config;
updateOffsetsLocked();
}
@@ -100,25 +99,21 @@
}
}
-VSyncModulator::Offsets VSyncModulator::getOffsets() {
+VSyncModulator::Offsets VSyncModulator::getOffsets() const {
std::lock_guard<std::mutex> lock(mMutex);
return mOffsets;
}
-VSyncModulator::Offsets VSyncModulator::getNextOffsets() {
- return mOffsetMap.at(getNextOffsetType());
-}
-
-VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() {
+const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const {
// Early offsets are used if we're in the middle of a refresh rate
// change, or if we recently begin a transaction.
if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 ||
mRefreshRateChangePending) {
- return OffsetType::Early;
+ return mOffsetsConfig.early;
} else if (mRemainingRenderEngineUsageCount > 0) {
- return OffsetType::EarlyGl;
+ return mOffsetsConfig.earlyGl;
} else {
- return OffsetType::Late;
+ return mOffsetsConfig.late;
}
}
@@ -128,37 +123,29 @@
}
void VSyncModulator::updateOffsetsLocked() {
- const Offsets desired = getNextOffsets();
+ const Offsets& offsets = getNextOffsets();
- if (mSfConnectionHandle != nullptr) {
- mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf);
- }
+ mScheduler.setPhaseOffset(mSfConnectionHandle, offsets.sf);
+ mScheduler.setPhaseOffset(mAppConnectionHandle, offsets.app);
- if (mAppConnectionHandle != nullptr) {
- mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app);
- }
+ mOffsets = offsets;
- flushOffsets();
-}
-
-void VSyncModulator::flushOffsets() {
- OffsetType type = getNextOffsetType();
- mOffsets = mOffsetMap.at(type);
if (!mTraceDetailedInfo) {
return;
}
- ATRACE_INT("Vsync-EarlyOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early);
- ATRACE_INT("Vsync-EarlyGLOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl);
- ATRACE_INT("Vsync-LateOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late);
- ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early);
- ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl);
- ATRACE_INT("Vsync-HighFpsLateOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late);
+
+ const bool isDefault = mOffsets.fpsMode == RefreshRateType::DEFAULT;
+ const bool isPerformance = mOffsets.fpsMode == RefreshRateType::PERFORMANCE;
+ const bool isEarly = &offsets == &mOffsetsConfig.early;
+ const bool isEarlyGl = &offsets == &mOffsetsConfig.earlyGl;
+ const bool isLate = &offsets == &mOffsetsConfig.late;
+
+ ATRACE_INT("Vsync-EarlyOffsetsOn", isDefault && isEarly);
+ ATRACE_INT("Vsync-EarlyGLOffsetsOn", isDefault && isEarlyGl);
+ ATRACE_INT("Vsync-LateOffsetsOn", isDefault && isLate);
+ ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", isPerformance && isEarly);
+ ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", isPerformance && isEarlyGl);
+ ATRACE_INT("Vsync-HighFpsLateOffsetsOn", isPerformance && isLate);
}
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index ddbd221..636c8c8 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -16,12 +16,11 @@
#pragma once
-#include <cinttypes>
#include <mutex>
#include "Scheduler.h"
-namespace android {
+namespace android::scheduler {
/*
* Modulates the vsync-offsets depending on current SurfaceFlinger state.
@@ -31,51 +30,36 @@
// Number of frames we'll keep the early phase offsets once they are activated for a
// transaction. This acts as a low-pass filter in case the client isn't quick enough in
// sending new transactions.
- const int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2;
+ static constexpr int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2;
// Number of frames we'll keep the early gl phase offsets once they are activated.
// This acts as a low-pass filter to avoid scenarios where we rapidly
// switch in and out of gl composition.
- const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2;
+ static constexpr int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2;
+
+ using RefreshRateType = RefreshRateConfigs::RefreshRateType;
public:
- VSyncModulator();
-
// Wrapper for a collection of surfaceflinger/app offsets for a particular
- // configuration .
+ // configuration.
struct Offsets {
- scheduler::RefreshRateConfigs::RefreshRateType fpsMode;
+ RefreshRateType fpsMode;
nsecs_t sf;
nsecs_t app;
};
- enum class OffsetType {
- Early,
- EarlyGl,
- Late,
+ struct OffsetsConfig {
+ Offsets early; // For transactions with the eEarlyWakeup flag.
+ Offsets earlyGl; // As above but while compositing with GL.
+ Offsets late; // Default.
+
+ nsecs_t thresholdForNextVsync;
};
- // Sets the phase offsets
- //
- // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
- // as early. May be the same as late, in which case we don't shift offsets.
- // sfEarlyGl: Like sfEarly, but only if we used GL composition. If we use both GL composition
- // and the transaction was marked as early, we'll use sfEarly.
- // sfLate: The regular SF vsync phase offset.
- // appEarly: Like sfEarly, but for the app-vsync
- // appEarlyGl: Like sfEarlyGl, but for the app-vsync.
- // appLate: The regular app vsync phase offset.
- void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
- nsecs_t thresholdForNextVsync) EXCLUDES(mMutex);
+ VSyncModulator(Scheduler&, const sp<Scheduler::ConnectionHandle>& appConnectionHandle,
+ const sp<Scheduler::ConnectionHandle>& sfConnectionHandle, const OffsetsConfig&);
- // Sets the scheduler and vsync connection handlers.
- void setSchedulerAndHandles(Scheduler* scheduler,
- Scheduler::ConnectionHandle* appConnectionHandle,
- Scheduler::ConnectionHandle* sfConnectionHandle) {
- mScheduler = scheduler;
- mAppConnectionHandle = appConnectionHandle;
- mSfConnectionHandle = sfConnectionHandle;
- }
+ void setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex);
// Signals that a transaction has started, and changes offsets accordingly.
void setTransactionStart(Scheduler::TransactionStart transactionStart);
@@ -98,28 +82,23 @@
void onRefreshed(bool usedRenderEngine);
// Returns the offsets that we are currently using
- Offsets getOffsets() EXCLUDES(mMutex);
+ Offsets getOffsets() const EXCLUDES(mMutex);
private:
// Returns the next offsets that we should be using
- Offsets getNextOffsets() REQUIRES(mMutex);
- // Returns the next offset type that we should use.
- OffsetType getNextOffsetType();
+ const Offsets& getNextOffsets() const REQUIRES(mMutex);
// Updates offsets and persists them into the scheduler framework.
void updateOffsets() EXCLUDES(mMutex);
void updateOffsetsLocked() REQUIRES(mMutex);
- // Updates the internal offsets and offset type.
- void flushOffsets() REQUIRES(mMutex);
+
+ Scheduler& mScheduler;
+ const sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
+ const sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
mutable std::mutex mMutex;
- std::unordered_map<OffsetType, Offsets> mOffsetMap GUARDED_BY(mMutex);
- nsecs_t mThresholdForNextVsync;
+ OffsetsConfig mOffsetsConfig GUARDED_BY(mMutex);
- Scheduler* mScheduler = nullptr;
- Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr;
- Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr;
-
- Offsets mOffsets GUARDED_BY(mMutex) = {Scheduler::RefreshRateType::DEFAULT, 0, 0};
+ Offsets mOffsets GUARDED_BY(mMutex){mOffsetsConfig.late};
std::atomic<Scheduler::TransactionStart> mTransactionStart =
Scheduler::TransactionStart::NORMAL;
@@ -130,4 +109,4 @@
bool mTraceDetailedInfo = false;
};
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 99440a6..7345e8d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -38,6 +38,7 @@
#include <binder/PermissionCache.h>
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/Layer.h>
@@ -162,28 +163,6 @@
return false;
}
-bool isHdrColorMode(const ColorMode colorMode) {
- switch (colorMode) {
- case ColorMode::BT2100_PQ:
- case ColorMode::BT2100_HLG:
- return true;
- case ColorMode::DISPLAY_P3:
- case ColorMode::ADOBE_RGB:
- case ColorMode::DCI_P3:
- case ColorMode::BT2020:
- case ColorMode::DISPLAY_BT2020:
- case ColorMode::NATIVE:
- case ColorMode::STANDARD_BT601_625:
- case ColorMode::STANDARD_BT601_625_UNADJUSTED:
- case ColorMode::STANDARD_BT601_525:
- case ColorMode::STANDARD_BT601_525_UNADJUSTED:
- case ColorMode::STANDARD_BT709:
- case ColorMode::SRGB:
- return false;
- }
- return false;
-}
-
ui::Transform::orientation_flags fromSurfaceComposerRotation(ISurfaceComposer::Rotation rotation) {
switch (rotation) {
case ISurfaceComposer::eRotateNone:
@@ -276,11 +255,11 @@
SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
: mFactory(factory),
- mPhaseOffsets(mFactory.createPhaseOffsets()),
mInterceptor(mFactory.createSurfaceInterceptor(this)),
mTimeStats(mFactory.createTimeStats()),
mEventQueue(mFactory.createMessageQueue()),
- mCompositionEngine(mFactory.createCompositionEngine()) {}
+ mCompositionEngine(mFactory.createCompositionEngine()),
+ mPhaseOffsets(mFactory.createPhaseOffsets()) {}
SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
ALOGI("SurfaceFlinger is starting");
@@ -386,10 +365,6 @@
property_get("debug.sf.luma_sampling", value, "1");
mLumaSampling = atoi(value);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late,
- mPhaseOffsets->getOffsetThresholdForNextVsync());
-
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -616,7 +591,7 @@
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset());
+ ALOGI("Phase offset: %" PRId64 " ns", mPhaseOffsets->getCurrentAppOffset());
Mutex::Autolock _l(mStateLock);
// start the EventThread
@@ -627,20 +602,21 @@
mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
mAppConnectionHandle =
- mScheduler->createConnection("app", mVsyncModulator.getOffsets().app,
+ mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
mPhaseOffsets->getOffsetThresholdForNextVsync(),
resyncCallback,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
- mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf,
+ mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
mPhaseOffsets->getOffsetThresholdForNextVsync(),
resyncCallback, [this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
- mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
- mSfConnectionHandle.get());
+
+ mVSyncModulator.emplace(*mScheduler, mAppConnectionHandle, mSfConnectionHandle,
+ mPhaseOffsets->getCurrentOffsets());
mRegionSamplingThread =
new RegionSamplingThread(*this, *mScheduler,
@@ -703,7 +679,11 @@
// set initial conditions (e.g. unblank default device)
initializeDisplays();
- getRenderEngine().primeCache();
+ char primeShaderCache[PROPERTY_VALUE_MAX];
+ property_get("service.sf.prime_shader_cache", primeShaderCache, "1");
+ if (atoi(primeShaderCache)) {
+ getRenderEngine().primeCache();
+ }
// Inform native graphics APIs whether the present timestamp is supported:
@@ -969,14 +949,11 @@
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
// As we called to set period, we will call to onRefreshRateChangeCompleted once
// DispSync model is locked.
- mVsyncModulator.onRefreshRateChangeInitiated();
+ mVSyncModulator->onRefreshRateChangeInitiated();
mPhaseOffsets->setRefreshRateType(info.type);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late,
- mPhaseOffsets->getOffsetThresholdForNextVsync());
+ mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets());
}
mDesiredActiveConfigChanged = true;
- ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
if (mRefreshRateOverlay) {
mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
@@ -1006,9 +983,7 @@
display->setActiveConfig(mUpcomingActiveConfig.configId);
mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late,
- mPhaseOffsets->getOffsetThresholdForNextVsync());
+ mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets());
ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
@@ -1021,13 +996,10 @@
std::lock_guard<std::mutex> lock(mActiveConfigLock);
mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
mDesiredActiveConfigChanged = false;
- ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late,
- mPhaseOffsets->getOffsetThresholdForNextVsync());
+ mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets());
}
bool SurfaceFlinger::performSetActiveConfig() {
@@ -1160,7 +1132,8 @@
decodeColorMode(mode).c_str(), mode);
} else {
display->getCompositionDisplay()->setColorMode(mode, Dataspace::UNKNOWN,
- RenderIntent::COLORIMETRIC);
+ RenderIntent::COLORIMETRIC,
+ Dataspace::UNKNOWN);
}
}));
@@ -1494,7 +1467,7 @@
bool periodFlushed = false;
mScheduler->addResyncSample(timestamp, &periodFlushed);
if (periodFlushed) {
- mVsyncModulator.onRefreshRateChangeCompleted();
+ mVSyncModulator->onRefreshRateChangeCompleted();
}
}
@@ -1686,22 +1659,22 @@
// woken up before the actual vsync but targeting the next vsync, we need to check
// fence N-2
const sp<Fence>& fence =
- mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
+ mVSyncModulator->getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
? mPreviousPresentFences[0]
: mPreviousPresentFences[1];
return fence != Fence::NO_FENCE && (fence->getStatus() == Fence::Status::Unsignaled);
}
-void SurfaceFlinger::populateExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS {
+void SurfaceFlinger::populateExpectedPresentTime() {
DisplayStatInfo stats;
mScheduler->getDisplayStatInfo(&stats);
const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime();
// Inflate the expected present time if we're targetting the next vsync.
- mExpectedPresentTime =
- mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
- ? presentTime
- : presentTime + stats.vsyncPeriod;
+ mExpectedPresentTime.store(mVSyncModulator->getOffsets().sf <
+ mPhaseOffsets->getOffsetThresholdForNextVsync()
+ ? presentTime
+ : presentTime + stats.vsyncPeriod);
}
void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
@@ -1713,12 +1686,12 @@
// seeing this same value.
populateExpectedPresentTime();
- bool frameMissed = previousFrameMissed();
- bool hwcFrameMissed = mHadDeviceComposition && frameMissed;
- bool gpuFrameMissed = mHadClientComposition && frameMissed;
- ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
- ATRACE_INT("HwcFrameMissed", static_cast<int>(hwcFrameMissed));
- ATRACE_INT("GpuFrameMissed", static_cast<int>(gpuFrameMissed));
+ const TracedOrdinal<bool> frameMissed = {"FrameMissed", previousFrameMissed()};
+ const TracedOrdinal<bool> hwcFrameMissed = {"HwcFrameMissed",
+ mHadDeviceComposition && frameMissed};
+ const TracedOrdinal<bool> gpuFrameMissed = {"GpuFrameMissed",
+ mHadClientComposition && frameMissed};
+
if (frameMissed) {
mFrameMissedCount++;
mTimeStats->incrementMissedFrames();
@@ -1804,8 +1777,17 @@
mRefreshPending = false;
+ compositionengine::CompositionRefreshArgs refreshArgs;
+ for (const auto& [_, display] : mDisplays) {
+ refreshArgs.outputs.push_back(display->getCompositionDisplay());
+ }
+ mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
+ auto compositionLayer = layer->getCompositionLayer();
+ if (compositionLayer) refreshArgs.layers.push_back(compositionLayer);
+ });
+
const bool repaintEverything = mRepaintEverything.exchange(false);
- preComposition();
+ mCompositionEngine->preComposition(refreshArgs);
rebuildLayerStacks();
calculateWorkingSet();
for (const auto& [token, display] : mDisplays) {
@@ -1831,7 +1813,7 @@
mHadDeviceComposition || getHwComposer().hasDeviceComposition(displayId);
}
- mVsyncModulator.onRefreshed(mHadClientComposition);
+ mVSyncModulator->onRefreshed(mHadClientComposition);
mLayersWithQueuedFrames.clear();
if (mVisibleRegionsDirty) {
@@ -1840,6 +1822,10 @@
mTracing.notify("visibleRegionsDirty");
}
}
+
+ if (mCompositionEngine->needsAnotherUpdate()) {
+ signalLayerUpdate();
+ }
}
@@ -1864,104 +1850,80 @@
ATRACE_CALL();
ALOGV(__FUNCTION__);
- // build the h/w work list
- if (CC_UNLIKELY(mGeometryInvalid)) {
- mGeometryInvalid = false;
+ const bool updatingGeometryThisFrame = mGeometryInvalid;
+ mGeometryInvalid = false;
+
+ {
+ // Use a map so that we latch the state of each front-end layer once.
+ std::unordered_map<compositionengine::LayerFE*, compositionengine::LayerFECompositionState*>
+ uniqueVisibleLayers;
+
+ // Figure out which frontend layers are being composed, and build the unique
+ // set of them (and the corresponding composition layer)
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ uniqueVisibleLayers.insert(std::make_pair(&layer->getLayerFE(),
+ &layer->getLayer().editState().frontEnd));
+ }
+ }
+ // Update the composition state from each front-end layer.
+ for (auto& [layerFE, state] : uniqueVisibleLayers) {
+ layerFE->latchCompositionState(*state, updatingGeometryThisFrame);
+ }
+ }
+
+ if (CC_UNLIKELY(updatingGeometryThisFrame)) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
uint32_t zOrder = 0;
for (auto& layer : display->getOutputLayersOrderedByZ()) {
- auto& compositionState = layer->editState();
- compositionState.forceClientComposition = false;
- if (!compositionState.hwc || mDebugDisableHWC || mDebugRegion) {
- compositionState.forceClientComposition = true;
- }
-
- // The output Z order is set here based on a simple counter.
- compositionState.z = zOrder++;
-
- // Update the display independent composition state. This goes
- // to the general composition layer state structure.
- // TODO: Do this once per compositionengine::CompositionLayer.
- layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd,
- true);
-
- // Recalculate the geometry state of the output layer.
- layer->updateCompositionState(true);
-
- // Write the updated geometry state to the HWC
- layer->writeStateToHWC(true);
+ // Assign a simple Z order sequence to each visible layer.
+ layer->editState().z = zOrder++;
}
}
}
- // Set the per-frame data
+ // Determine the color configuration of each output
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
- const auto displayId = display->getId();
- if (!displayId) {
- continue;
- }
- auto* profile = display->getDisplayColorProfile();
- if (mDrawingState.colorMatrixChanged) {
+ ColorMode colorMode = ColorMode::NATIVE;
+ Dataspace dataspace = Dataspace::UNKNOWN;
+ RenderIntent renderIntent = RenderIntent::COLORIMETRIC;
+ if (useColorManagement) {
+ pickColorMode(displayDevice, &colorMode, &dataspace, &renderIntent);
+ }
+ display->setColorMode(colorMode, dataspace, renderIntent, mColorSpaceAgnosticDataspace);
+ }
+
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ // Update the composition state of the output layer, as needed
+ // recomputing it from the state given by the front-end layer.
+ layer->updateCompositionState(updatingGeometryThisFrame);
+ }
+ }
+
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ // Send the updated state to the HWC, if appropriate.
+ layer->writeStateToHWC(updatingGeometryThisFrame);
+ }
+ }
+
+ if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
display->setColorTransform(mDrawingState.colorMatrix);
}
- Dataspace targetDataspace = Dataspace::UNKNOWN;
- if (useColorManagement) {
- ColorMode colorMode;
- RenderIntent renderIntent;
- pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent);
- display->setColorMode(colorMode, targetDataspace, renderIntent);
-
- if (isHdrColorMode(colorMode)) {
- targetDataspace = Dataspace::UNKNOWN;
- } else if (mColorSpaceAgnosticDataspace != Dataspace::UNKNOWN) {
- targetDataspace = mColorSpaceAgnosticDataspace;
- }
- }
-
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- if (layer->isHdrY410()) {
- layer->forceClientComposition(displayDevice);
- } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
- layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
- !profile->hasHDR10Support()) {
- layer->forceClientComposition(displayDevice);
- } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
- layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
- !profile->hasHLGSupport()) {
- layer->forceClientComposition(displayDevice);
- }
-
- if (layer->getRoundedCornerState().radius > 0.0f) {
- layer->forceClientComposition(displayDevice);
- }
-
- if (layer->getForceClientComposition(displayDevice)) {
- ALOGV("[%s] Requesting Client composition", layer->getName().string());
- layer->setCompositionType(displayDevice,
- Hwc2::IComposerClient::Composition::CLIENT);
- continue;
- }
-
- const auto& displayState = display->getState();
- layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
- displayDevice->getSupportedPerFrameMetadata(), targetDataspace);
- }
- }
-
- mDrawingState.colorMatrixChanged = false;
-
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- auto& layerState = layer->getCompositionLayer()->editState().frontEnd;
- layerState.compositionType = static_cast<Hwc2::IComposerClient::Composition>(
- layer->getCompositionType(displayDevice));
- }
+ mDrawingState.colorMatrixChanged = false;
}
}
@@ -2009,25 +1971,6 @@
}
}
-void SurfaceFlinger::preComposition()
-{
- ATRACE_CALL();
- ALOGV("preComposition");
-
- mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
-
- bool needExtraInvalidate = false;
- mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (layer->onPreComposition(mRefreshStartTime)) {
- needExtraInvalidate = true;
- }
- });
-
- if (needExtraInvalidate) {
- signalLayerUpdate();
- }
-}
-
void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
std::shared_ptr<FenceTime>& presentFenceTime) {
// Update queue of past composite+present times and determine the
@@ -2121,10 +2064,11 @@
DisplayStatInfo stats;
mScheduler->getDisplayStatInfo(&stats);
- // We use the mRefreshStartTime which might be sampled a little later than
- // when we started doing work for this frame, but that should be okay
- // since updateCompositorTiming has snapping logic.
- updateCompositorTiming(stats, mRefreshStartTime, presentFenceTime);
+ // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might
+ // be sampled a little later than when we started doing work for this frame,
+ // but that should be okay since updateCompositorTiming has snapping logic.
+ updateCompositorTiming(stats, mCompositionEngine->getLastFrameRefreshTimestamp(),
+ presentFenceTime);
CompositorTiming compositorTiming;
{
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
@@ -2257,8 +2201,8 @@
Region opaqueRegion;
Region dirtyRegion;
compositionengine::Output::OutputLayers layersSortedByZ;
+ compositionengine::Output::ReleasedLayers releasedLayers;
Vector<sp<Layer>> deprecated_layersSortedByZ;
- Vector<sp<Layer>> layersNeedingFences;
const ui::Transform& tr = displayState.transform;
const Rect bounds = displayState.bounds;
if (displayState.isEnabled) {
@@ -2306,16 +2250,16 @@
layer) != mLayersWithQueuedFrames.cend();
if (hasExistingOutputLayer && hasQueuedFrames) {
- layersNeedingFences.add(layer);
+ releasedLayers.push_back(layer);
}
}
});
}
display->setOutputLayersOrderedByZ(std::move(layersSortedByZ));
+ display->setReleasedLayers(std::move(releasedLayers));
displayDevice->setVisibleLayersSortedByZ(deprecated_layersSortedByZ);
- displayDevice->setLayersNeedingFences(layersNeedingFences);
Region undefinedRegion{bounds};
undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
@@ -2358,7 +2302,8 @@
case Dataspace::BT2020_ITU_PQ:
bestDataSpace = Dataspace::DISPLAY_P3;
*outHdrDataSpace = Dataspace::BT2020_PQ;
- *outIsHdrClientComposition = layer->getForceClientComposition(display);
+ *outIsHdrClientComposition =
+ layer->getCompositionLayer()->getState().frontEnd.forceClientComposition;
break;
case Dataspace::BT2020_HLG:
case Dataspace::BT2020_ITU_HLG:
@@ -2550,11 +2495,14 @@
// We've got a list of layers needing fences, that are disjoint with
// display->getVisibleLayersSortedByZ. The best we can do is to
// supply them with the present fence.
- if (!displayDevice->getLayersNeedingFences().isEmpty()) {
+ auto releasedLayers = display->takeReleasedLayers();
+ if (!releasedLayers.empty()) {
sp<Fence> presentFence =
displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE;
- for (auto& layer : displayDevice->getLayersNeedingFences()) {
- layer->getCompositionLayer()->getLayerFE()->onLayerDisplayed(presentFence);
+ for (auto& weakLayer : releasedLayers) {
+ if (auto layer = weakLayer.promote(); layer != nullptr) {
+ layer->onLayerDisplayed(presentFence);
+ }
}
}
@@ -2583,7 +2531,7 @@
// with mStateLock held to guarantee that mCurrentState won't change
// until the transaction is committed.
- mVsyncModulator.onTransactionHandled();
+ mVSyncModulator->onTransactionHandled();
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
@@ -2699,7 +2647,7 @@
defaultDataSpace = Dataspace::V0_SRGB;
}
display->getCompositionDisplay()->setColorMode(defaultColorMode, defaultDataSpace,
- RenderIntent::COLORIMETRIC);
+ RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN);
if (!state.isVirtual()) {
LOG_ALWAYS_FATAL_IF(!displayId);
display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));
@@ -2856,9 +2804,11 @@
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
+ const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
+
// Notify all layers of available frames
- mCurrentState.traverseInZOrder([](Layer* layer) {
- layer->notifyAvailableFrames();
+ mCurrentState.traverseInZOrder([expectedPresentTime](Layer* layer) {
+ layer->notifyAvailableFrames(expectedPresentTime);
});
/*
@@ -3057,7 +3007,7 @@
void SurfaceFlinger::latchAndReleaseBuffer(const sp<Layer>& layer) {
if (layer->hasReadyFrame()) {
bool ignored = false;
- layer->latchBuffer(ignored, systemTime());
+ layer->latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */);
}
layer->releasePendingBuffer(systemTime());
}
@@ -3305,6 +3255,8 @@
bool frameQueued = false;
bool newDataLatched = false;
+ const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
+
// Store the set of layers that need updates. This set must not change as
// buffers are being latched, as this could result in a deadlock.
// Example: Two producers share the same command stream and:
@@ -3317,7 +3269,6 @@
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (layer->hasReadyFrame()) {
frameQueued = true;
- const nsecs_t expectedPresentTime = getExpectedPresentTime();
if (layer->shouldPresentNow(expectedPresentTime)) {
mLayersWithQueuedFrames.push_back(layer);
} else {
@@ -3335,7 +3286,7 @@
Mutex::Autolock lock(mStateLock);
for (auto& layer : mLayersWithQueuedFrames) {
- if (layer->latchBuffer(visibleRegions, latchTime)) {
+ if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) {
mLayersPendingRefresh.push_back(layer);
}
layer->useSurfaceDamage();
@@ -3402,8 +3353,9 @@
const Region bounds(displayState.bounds);
const DisplayRenderArea renderArea(displayDevice);
- const bool hasClientComposition = getHwComposer().hasClientComposition(displayId);
- ATRACE_INT("hasClientComposition", hasClientComposition);
+ const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
+ getHwComposer().hasClientComposition(
+ displayId)};
bool applyColorMatrix = false;
@@ -3633,7 +3585,7 @@
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
Scheduler::TransactionStart transactionStart) {
uint32_t old = mTransactionFlags.fetch_or(flags);
- mVsyncModulator.setTransactionStart(transactionStart);
+ mVSyncModulator->setTransactionStart(transactionStart);
if ((old & flags)==0) { // wake the server up
signalTransaction();
}
@@ -3656,6 +3608,7 @@
while (!transactionQueue.empty()) {
const auto& transaction = transactionQueue.front();
if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime,
+ true /* useCachedExpectedPresentTime */,
transaction.states)) {
setTransactionFlags(eTransactionFlushNeeded);
break;
@@ -3685,31 +3638,14 @@
return !mTransactionQueues.empty();
}
-bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>& states) {
- for (const ComposerState& state : states) {
- // Here we need to check that the interface we're given is indeed
- // one of our own. A malicious client could give us a nullptr
- // IInterface, or one of its own or even one of our own but a
- // different type. All these situations would cause us to crash.
- if (state.client == nullptr) {
- return true;
- }
-
- sp<IBinder> binder = IInterface::asBinder(state.client);
- if (binder == nullptr) {
- return true;
- }
-
- if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) == nullptr) {
- return true;
- }
- }
- return false;
-}
bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+ bool useCachedExpectedPresentTime,
const Vector<ComposerState>& states) {
- nsecs_t expectedPresentTime = getExpectedPresentTime();
+ if (!useCachedExpectedPresentTime)
+ populateExpectedPresentTime();
+
+ const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
// Do not present if the desiredPresentTime has not passed unless it is more than one second
// in the future. We ignore timestamps more than 1 second in the future for stability reasons.
if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime &&
@@ -3744,10 +3680,6 @@
Mutex::Autolock _l(mStateLock);
- if (containsAnyInvalidClientState(states)) {
- return;
- }
-
// If its TransactionQueue already has a pending TransactionState or if it is pending
auto itr = mTransactionQueues.find(applyToken);
// if this is an animation frame, wait until prior animation frame has
@@ -3764,8 +3696,10 @@
itr = mTransactionQueues.find(applyToken);
}
}
- if (itr != mTransactionQueues.end() ||
- !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
+
+ // Expected present time is computed and cached on invalidate, so it may be stale.
+ if (itr != mTransactionQueues.end() || !transactionIsReadyToBeApplied(
+ desiredPresentTime, false /* useCachedExpectedPresentTime */, states)) {
mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
uncacheBuffer, listenerCallbacks, postTime,
privileged);
@@ -3959,9 +3893,8 @@
const std::vector<ListenerCallbacks>& listenerCallbacks, int64_t postTime,
bool privileged) {
const layer_state_t& s = composerState.state;
- sp<Client> client(static_cast<Client*>(composerState.client.get()));
- sp<Layer> layer(client->getLayerUser(s.surface));
+ sp<Layer> layer(fromHandle(s.surface));
if (layer == nullptr) {
for (auto& listenerCallback : listenerCallbacks) {
mTransactionCompletedThread.registerUnpresentedCallbackHandle(
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0e6eacf..04e0c89 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -60,6 +60,7 @@
#include "Scheduler/VSyncModulator.h"
#include "SurfaceFlingerFactory.h"
#include "SurfaceTracing.h"
+#include "TracedOrdinal.h"
#include "TransactionCompletedThread.h"
#include <atomic>
@@ -68,6 +69,7 @@
#include <map>
#include <memory>
#include <mutex>
+#include <optional>
#include <queue>
#include <set>
#include <string>
@@ -295,18 +297,13 @@
// main thread function to enable/disable h/w composer event
void setPrimaryVsyncEnabledInternal(bool enabled);
+ void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled);
// called on the main thread by MessageQueue when an internal message
// is received
// TODO: this should be made accessible only to MessageQueue
void onMessageReceived(int32_t what);
- // populates the expected present time for this frame.
- // When we are in negative offsets, we perform a correction so that the
- // predicted vsync for the *next* frame is used instead.
- void populateExpectedPresentTime();
- nsecs_t getExpectedPresentTime() const { return mExpectedPresentTime; }
-
// for debugging only
// TODO: this should be made accessible only to HWComposer
const Vector<sp<Layer>>& getLayerSortedByZForHwcDisplay(DisplayId displayId);
@@ -583,8 +580,8 @@
void latchAndReleaseBuffer(const sp<Layer>& layer);
void commitTransaction() REQUIRES(mStateLock);
void commitOffscreenLayers();
- bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+ bool useCachedExpectedPresentTime,
const Vector<ComposerState>& states);
uint32_t setClientStateLocked(const ComposerState& composerState, int64_t desiredPresentTime,
const std::vector<ListenerCallbacks>& listenerCallbacks,
@@ -748,7 +745,6 @@
void computeVisibleRegions(const sp<const DisplayDevice>& display, Region& dirtyRegion,
Region& opaqueRegion);
- void preComposition();
void postComposition();
void getCompositorTiming(CompositorTiming* compositorTiming);
void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
@@ -816,6 +812,12 @@
bool isDisplayConfigAllowed(int32_t configId) const REQUIRES(mStateLock);
+ bool previousFrameMissed();
+
+ // Populates the expected present time for this frame. For negative offsets, performs a
+ // correction using the predicted vsync for the next frame instead.
+ void populateExpectedPresentTime();
+
/*
* Display identification
*/
@@ -844,9 +846,6 @@
return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
}
- bool previousFrameMissed();
- void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled);
-
/*
* Debugging & dumpsys
*/
@@ -963,11 +962,6 @@
std::unique_ptr<EventThread> mInjectorEventThread;
std::unique_ptr<InjectVSyncSource> mVSyncInjector;
- // Calculates correct offsets.
- VSyncModulator mVsyncModulator;
- // Keeps track of all available phase offsets for different refresh types.
- const std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets;
-
// Can only accessed from the main thread, these members
// don't need synchronization
State mDrawingState{LayerVector::StateSet::Drawing};
@@ -1132,9 +1126,17 @@
sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
+ // Stores phase offsets configured per refresh rate.
+ const std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets;
+
+ // Optional to defer construction until scheduler connections are created.
+ std::optional<scheduler::VSyncModulator> mVSyncModulator;
+
scheduler::RefreshRateConfigs mRefreshRateConfigs;
scheduler::RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, *mTimeStats};
+ std::atomic<nsecs_t> mExpectedPresentTime = 0;
+
// All configs are allowed if the set is empty.
using DisplayConfigs = std::set<int32_t>;
DisplayConfigs mAllowedDisplayConfigs GUARDED_BY(mStateLock);
@@ -1148,7 +1150,8 @@
ActiveConfigInfo mDesiredActiveConfig GUARDED_BY(mActiveConfigLock);
// below flags are set by main thread only
- bool mDesiredActiveConfigChanged GUARDED_BY(mActiveConfigLock) = false;
+ TracedOrdinal<bool> mDesiredActiveConfigChanged
+ GUARDED_BY(mActiveConfigLock) = {"DesiredActiveConfigChanged", false};
bool mCheckPendingFence = false;
bool mLumaSampling = true;
@@ -1188,8 +1191,6 @@
// Flags to capture the state of Vsync in HWC
HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable;
HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable;
-
- nsecs_t mExpectedPresentTime;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 7f86c14..fdc6c58 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -39,6 +39,12 @@
struct DisplayDeviceState;
struct DisplayState;
struct layer_state_t;
+using Transaction = surfaceflinger::Transaction;
+using Trace = surfaceflinger::Trace;
+using Rectangle = surfaceflinger::Rectangle;
+using SurfaceChange = surfaceflinger::SurfaceChange;
+using Increment = surfaceflinger::Increment;
+using DisplayChange = surfaceflinger::DisplayChange;
constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
@@ -183,6 +189,7 @@
};
} // namespace impl
+
} // namespace android
#endif // ANDROID_SURFACEINTERCEPTOR_H
diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h
new file mode 100644
index 0000000..c145a39
--- /dev/null
+++ b/services/surfaceflinger/TracedOrdinal.h
@@ -0,0 +1,64 @@
+/*
+ * 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 <android-base/stringprintf.h>
+#include <utils/Trace.h>
+#include <cmath>
+#include <string>
+
+template <typename T>
+class TracedOrdinal {
+public:
+ static_assert(std::is_same<bool, T>() || (std::is_signed<T>() && std::is_integral<T>()),
+ "Type is not supported. Please test it with systrace before adding "
+ "it to the list.");
+
+ TracedOrdinal(const std::string& name, T initialValue)
+ : mName(name),
+ mNameNegative(android::base::StringPrintf("%sNegative", name.c_str())),
+ mHasGoneNegative(std::signbit(initialValue)),
+ mData(initialValue) {
+ trace();
+ }
+
+ operator T() const { return mData; }
+
+ TracedOrdinal& operator=(T other) {
+ mData = other;
+ mHasGoneNegative = mHasGoneNegative || std::signbit(mData);
+ trace();
+ return *this;
+ }
+
+private:
+ void trace() {
+ if (!std::signbit(mData)) {
+ ATRACE_INT64(mName.c_str(), int64_t(mData));
+ if (mHasGoneNegative) {
+ ATRACE_INT64(mNameNegative.c_str(), 0);
+ }
+ } else {
+ ATRACE_INT64(mNameNegative.c_str(), -int64_t(mData));
+ ATRACE_INT64(mName.c_str(), 0);
+ }
+ }
+
+ const std::string mName;
+ const std::string mNameNegative;
+ bool mHasGoneNegative;
+ T mData;
+};
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 26c6da9..bc5f1aa 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -36,6 +36,9 @@
namespace android {
using Transaction = SurfaceComposerClient::Transaction;
+using SurfaceChange = surfaceflinger::SurfaceChange;
+using Trace = surfaceflinger::Trace;
+using Increment = surfaceflinger::Increment;
constexpr int32_t SCALING_UPDATE = 1;
constexpr uint32_t BUFFER_UPDATES = 18;
@@ -980,5 +983,4 @@
ASSERT_TRUE(bufferUpdatesFound(capturedTrace));
ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation));
}
-
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index e6211c4..0f21ad8 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -502,7 +502,7 @@
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
bool ignoredRecomputeVisibleRegions;
- layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
+ layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, 0);
Mock::VerifyAndClear(test->mRenderEngine);
}
@@ -988,7 +988,9 @@
struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
static void setupLayerState(CompositionTest* test, sp<Layer> layer) {
- layer->forceClientComposition(test->mDisplay);
+ const auto outputLayer = layer->findOutputLayerForDisplay(test->mDisplay);
+ LOG_FATAL_IF(!outputLayer);
+ outputLayer->editState().forceClientComposition = true;
}
template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
index 1d75011..66c7f6b 100644
--- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -20,42 +20,22 @@
#include "Scheduler/PhaseOffsets.h"
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
-using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+struct FakePhaseOffsets : PhaseOffsets {
+ static constexpr nsecs_t FAKE_PHASE_OFFSET_NS = 0;
-class FakePhaseOffsets : public android::scheduler::PhaseOffsets {
- nsecs_t FAKE_PHASE_OFFSET_NS = 0;
+ Offsets getOffsetsForRefreshRate(RefreshRateType) const override { return getCurrentOffsets(); }
-public:
- FakePhaseOffsets() = default;
- ~FakePhaseOffsets() = default;
-
- nsecs_t getCurrentAppOffset() override { return FAKE_PHASE_OFFSET_NS; }
- nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; }
-
- PhaseOffsets::Offsets getOffsetsForRefreshRate(
- RefreshRateType /*refreshRateType*/) const override {
- return getCurrentOffsets();
+ Offsets getCurrentOffsets() const override {
+ return {{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ FAKE_PHASE_OFFSET_NS};
}
- // Returns early, early GL, and late offsets for Apps and SF.
- PhaseOffsets::Offsets getCurrentOffsets() const override {
- return Offsets{{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- {RefreshRateType::DEFAULT, 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(RefreshRateType /*refreshRateType*/) override {}
-
- nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; }
-
- // Returns current offsets in human friendly format.
- void dump(std::string& /*result*/) const override {}
+ void setRefreshRateType(RefreshRateType) override {}
+ void dump(std::string&) const override {}
};
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler