Merge "EGL: default to HAL_DATASPACE_UNKNOWN." into pi-dev
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 711143c..be3bbf7 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -24,6 +24,7 @@
#include <binder/IPermissionController.h>
#endif
#include <binder/Parcel.h>
+#include <cutils/properties.h>
#include <utils/String8.h>
#include <utils/SystemClock.h>
#include <utils/CallStack.h>
@@ -142,20 +143,35 @@
virtual sp<IBinder> getService(const String16& name) const
{
- unsigned n;
- for (n = 0; n < 5; n++){
- if (n > 0) {
- if (!strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder")) {
- ALOGI("Waiting for vendor service %s...", String8(name).string());
- CallStack stack(LOG_TAG);
- } else {
- ALOGI("Waiting for service %s...", String8(name).string());
- }
- sleep(1);
+ sp<IBinder> svc = checkService(name);
+ if (svc != NULL) return svc;
+
+ const bool isVendorService =
+ strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
+ const long timeout = uptimeMillis() + 5000;
+ if (!gSystemBootCompleted) {
+ char bootCompleted[PROPERTY_VALUE_MAX];
+ property_get("sys.boot_completed", bootCompleted, "0");
+ gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false;
+ }
+ // retry interval in millisecond.
+ const long sleepTime = gSystemBootCompleted ? 1000 : 100;
+
+ int n = 0;
+ while (uptimeMillis() < timeout) {
+ n++;
+ if (isVendorService) {
+ ALOGI("Waiting for vendor service %s...", String8(name).string());
+ CallStack stack(LOG_TAG);
+ } else if (n%10 == 0) {
+ ALOGI("Waiting for service %s...", String8(name).string());
}
+ usleep(1000*sleepTime);
+
sp<IBinder> svc = checkService(name);
if (svc != NULL) return svc;
}
+ ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
return NULL;
}
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
index 9899b65..c5c3fd5 100644
--- a/libs/binder/Static.cpp
+++ b/libs/binder/Static.cpp
@@ -97,5 +97,6 @@
#ifndef __ANDROID_VNDK__
sp<IPermissionController> gPermissionController;
#endif
+bool gSystemBootCompleted = false;
} // namespace android
diff --git a/libs/binder/include/private/binder/Static.h b/libs/binder/include/private/binder/Static.h
index f04bcae..6ca7592 100644
--- a/libs/binder/include/private/binder/Static.h
+++ b/libs/binder/include/private/binder/Static.h
@@ -41,5 +41,6 @@
#ifndef __ANDROID_VNDK__
extern sp<IPermissionController> gPermissionController;
#endif
+extern bool gSystemBootCompleted;
} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 5f09ac0..abb0290 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -232,104 +232,170 @@
}
}
-// Generate OOTF that modifies the relative scence light to relative display light.
-void ProgramCache::generateOOTF(Formatter& fs, const Key& needs) {
- fs << R"__SHADER__(
- highp float CalculateY(const highp vec3 color) {
- // BT2020 standard uses the unadjusted KR = 0.2627,
- // KB = 0.0593 luminance interpretation for RGB conversion.
- return color.r * 0.262700 + color.g * 0.677998 + color.b * 0.059302;
- }
- )__SHADER__";
-
- // Generate OOTF that modifies the relative display light.
- switch(needs.getInputTF()) {
+void ProgramCache::generateToneMappingProcess(Formatter& fs, const Key& needs) {
+ // Convert relative light to absolute light.
+ switch (needs.getInputTF()) {
case Key::INPUT_TF_ST2084:
fs << R"__SHADER__(
- highp vec3 OOTF(const highp vec3 color) {
- const float maxLumi = 10000.0;
- const float maxMasteringLumi = 1000.0;
- const float maxContentLumi = 1000.0;
- const float maxInLumi = min(maxMasteringLumi, maxContentLumi);
- float maxOutLumi = displayMaxLuminance;
-
- // Calculate Y value in XYZ color space.
- float colorY = CalculateY(color);
-
- // convert to nits first
- float nits = colorY * maxLumi;
-
- // clamp to max input luminance
- nits = clamp(nits, 0.0, maxInLumi);
-
- // scale [0.0, maxInLumi] to [0.0, maxOutLumi]
- if (maxInLumi <= maxOutLumi) {
- nits *= maxOutLumi / maxInLumi;
- } else {
- // three control points
- const float x0 = 10.0;
- const float y0 = 17.0;
- float x1 = maxOutLumi * 0.75;
- float y1 = x1;
- float x2 = x1 + (maxInLumi - x1) / 2.0;
- float y2 = y1 + (maxOutLumi - y1) * 0.75;
-
- // horizontal distances between the last three control points
- float h12 = x2 - x1;
- float h23 = maxInLumi - x2;
- // tangents at the last three control points
- float m1 = (y2 - y1) / h12;
- float m3 = (maxOutLumi - y2) / h23;
- float m2 = (m1 + m3) / 2.0;
-
- if (nits < x0) {
- // scale [0.0, x0] to [0.0, y0] linearly
- const float slope = y0 / x0;
- nits *= slope;
- } else if (nits < x1) {
- // scale [x0, x1] to [y0, y1] linearly
- float slope = (y1 - y0) / (x1 - x0);
- nits = y0 + (nits - x0) * slope;
- } else if (nits < x2) {
- // scale [x1, x2] to [y1, y2] using Hermite interp
- float t = (nits - x1) / h12;
- nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) +
- (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t;
- } else {
- // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp
- float t = (nits - x2) / h23;
- nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) +
- (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t;
- }
- }
-
- // convert back to [0.0, 1.0]
- float targetY = nits / maxOutLumi;
- return color * (targetY / max(1e-6, colorY));
+ highp vec3 ScaleLuminance(highp vec3 color) {
+ return color * 10000.0;
}
)__SHADER__";
break;
case Key::INPUT_TF_HLG:
fs << R"__SHADER__(
- highp vec3 OOTF(const highp vec3 color) {
- const float maxOutLumi = 500.0;
- const float gamma = 1.2 + 0.42 * log(maxOutLumi / 1000.0) / log(10.0);
+ highp vec3 ScaleLuminance(highp vec3 color) {
// The formula is:
// alpha * pow(Y, gamma - 1.0) * color + beta;
- // where alpha is 1.0, beta is 0.0 as recommended in
- // Rec. ITU-R BT.2100-1 TABLE 5.
- return pow(CalculateY(color), gamma - 1.0) * color;
+ // where alpha is 1000.0, gamma is 1.2, beta is 0.0.
+ return color * 1000.0 * pow(color.y, 0.2);
}
)__SHADER__";
break;
default:
fs << R"__SHADER__(
- highp vec3 OOTF(const highp vec3 color) {
+ highp vec3 ScaleLuminance(highp vec3 color) {
+ return color * displayMaxLuminance;
+ }
+ )__SHADER__";
+ break;
+ }
+
+ // Tone map absolute light to display luminance range.
+ switch (needs.getInputTF()) {
+ case Key::INPUT_TF_ST2084:
+ case Key::INPUT_TF_HLG:
+ switch (needs.getOutputTF()) {
+ case Key::OUTPUT_TF_HLG:
+ // Right now when mixed PQ and HLG contents are presented,
+ // HLG content will always be converted to PQ. However, for
+ // completeness, we simply clamp the value to [0.0, 1000.0].
+ fs << R"__SHADER__(
+ highp vec3 ToneMap(highp vec3 color) {
+ return clamp(color, 0.0, 1000.0);
+ }
+ )__SHADER__";
+ break;
+ case Key::OUTPUT_TF_ST2084:
+ fs << R"__SHADER__(
+ highp vec3 ToneMap(highp vec3 color) {
+ return color;
+ }
+ )__SHADER__";
+ break;
+ default:
+ fs << R"__SHADER__(
+ highp vec3 ToneMap(highp vec3 color) {
+ const float maxMasteringLumi = 1000.0;
+ const float maxContentLumi = 1000.0;
+ const float maxInLumi = min(maxMasteringLumi, maxContentLumi);
+ float maxOutLumi = displayMaxLuminance;
+
+ float nits = color.y;
+
+ // clamp to max input luminance
+ nits = clamp(nits, 0.0, maxInLumi);
+
+ // scale [0.0, maxInLumi] to [0.0, maxOutLumi]
+ if (maxInLumi <= maxOutLumi) {
+ nits *= maxOutLumi / maxInLumi;
+ } else {
+ // three control points
+ const float x0 = 10.0;
+ const float y0 = 17.0;
+ float x1 = maxOutLumi * 0.75;
+ float y1 = x1;
+ float x2 = x1 + (maxInLumi - x1) / 2.0;
+ float y2 = y1 + (maxOutLumi - y1) * 0.75;
+
+ // horizontal distances between the last three control points
+ const float h12 = x2 - x1;
+ const float h23 = maxInLumi - x2;
+ // tangents at the last three control points
+ const float m1 = (y2 - y1) / h12;
+ const float m3 = (maxOutLumi - y2) / h23;
+ const float m2 = (m1 + m3) / 2.0;
+
+ if (nits < x0) {
+ // scale [0.0, x0] to [0.0, y0] linearly
+ const float slope = y0 / x0;
+ nits *= slope;
+ } else if (nits < x1) {
+ // scale [x0, x1] to [y0, y1] linearly
+ const float slope = (y1 - y0) / (x1 - x0);
+ nits = y0 + (nits - x0) * slope;
+ } else if (nits < x2) {
+ // scale [x1, x2] to [y1, y2] using Hermite interp
+ float t = (nits - x1) / h12;
+ nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) +
+ (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t;
+ } else {
+ // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp
+ float t = (nits - x2) / h23;
+ nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) +
+ (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t;
+ }
+ }
+
+ return color * (nits / max(1e-6, color.y));
+ }
+ )__SHADER__";
+ break;
+ }
+ break;
+ default:
+ // TODO(73825729) We need to revert the tone mapping in
+ // hardware composer properly.
+ fs << R"__SHADER__(
+ highp vec3 ToneMap(highp vec3 color) {
return color;
}
)__SHADER__";
break;
}
+
+ // convert absolute light to relative light.
+ switch (needs.getOutputTF()) {
+ case Key::OUTPUT_TF_ST2084:
+ fs << R"__SHADER__(
+ highp vec3 NormalizeLuminance(highp vec3 color) {
+ return color / 10000.0;
+ }
+ )__SHADER__";
+ break;
+ case Key::OUTPUT_TF_HLG:
+ fs << R"__SHADER__(
+ highp vec3 NormalizeLuminance(highp vec3 color) {
+ return color / 1000.0 * pow(color.y / 1000.0, -0.2 / 1.2);
+ }
+ )__SHADER__";
+ break;
+ default:
+ fs << R"__SHADER__(
+ highp vec3 NormalizeLuminance(highp vec3 color) {
+ return color / displayMaxLuminance;
+ }
+ )__SHADER__";
+ break;
+ }
+}
+
+// Generate OOTF that modifies the relative scence light to relative display light.
+void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) {
+ if (!needs.needsToneMapping()) {
+ fs << R"__SHADER__(
+ highp vec3 OOTF(const highp vec3 color) {
+ return color;
+ }
+ )__SHADER__";
+ } else {
+ generateToneMappingProcess(fs, needs);
+ fs << R"__SHADER__(
+ highp vec3 OOTF(const highp vec3 color) {
+ return NormalizeLuminance(ToneMap(ScaleLuminance(color)));
+ }
+ )__SHADER__";
+ }
}
// Generate OETF that converts relative display light to signal values,
@@ -446,8 +512,8 @@
}
if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
- // Currently, only the OOTF of BT2020 PQ needs display maximum luminance.
- if (needs.getInputTF() == Key::INPUT_TF_ST2084) {
+ // Currently, display maximum luminance is needed when doing tone mapping.
+ if (needs.needsToneMapping()) {
fs << "uniform float displayMaxLuminance;";
}
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
index e1398eb..864bc3f 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -126,6 +126,29 @@
}
inline int getInputTF() const { return (mKey & INPUT_TF_MASK); }
inline int getOutputTF() const { return (mKey & OUTPUT_TF_MASK); }
+
+ // When HDR and non-HDR contents are mixed, or different types of HDR contents are
+ // mixed, we will do a tone mapping process to tone map the input content to output
+ // content. Currently, the following conversions handled, they are:
+ // * SDR -> HLG
+ // * SDR -> PQ
+ // * HLG -> PQ
+ inline bool needsToneMapping() const {
+ int inputTF = getInputTF();
+ int outputTF = getOutputTF();
+
+ // Return false when converting from SDR to SDR.
+ if (inputTF == Key::INPUT_TF_SRGB && outputTF == Key::OUTPUT_TF_LINEAR) {
+ return false;
+ }
+ if (inputTF == Key::INPUT_TF_LINEAR && outputTF == Key::OUTPUT_TF_SRGB) {
+ return false;
+ }
+
+ inputTF >>= Key::INPUT_TF_SHIFT;
+ outputTF >>= Key::OUTPUT_TF_SHIFT;
+ return inputTF != outputTF;
+ }
inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; }
// this is the definition of a friend function -- not a method of class Needs
@@ -148,6 +171,8 @@
static Key computeKey(const Description& description);
// Generate EOTF based from Key.
static void generateEOTF(Formatter& fs, const Key& needs);
+ // Generate necessary tone mapping methods for OOTF.
+ static void generateToneMappingProcess(Formatter& fs, const Key& needs);
// Generate OOTF based from Key.
static void generateOOTF(Formatter& fs, const Key& needs);
// Generate OETF based from Key.
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index a6833a5..d4f1e29 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -59,14 +59,15 @@
}
if (argsMap.count("-dump")) {
- int64_t maxLayers = 0;
+ std::optional<uint32_t> maxLayers = std::nullopt;
auto iter = argsMap.find("-maxlayers");
if (iter != argsMap.end() && iter->second + 1 < static_cast<int32_t>(args.size())) {
- maxLayers = strtol(String8(args[iter->second + 1]).c_str(), nullptr, 10);
- maxLayers = std::clamp(maxLayers, int64_t(0), int64_t(UINT32_MAX));
+ int64_t value = strtol(String8(args[iter->second + 1]).c_str(), nullptr, 10);
+ value = std::clamp(value, int64_t(0), int64_t(UINT32_MAX));
+ maxLayers = static_cast<uint32_t>(value);
}
- dump(asProto, static_cast<uint32_t>(maxLayers), result);
+ dump(asProto, maxLayers, result);
}
if (argsMap.count("-clear")) {
@@ -147,12 +148,27 @@
return static_cast<int32_t>(delta);
}
+static std::string getPackageName(const std::string& layerName) {
+ // This regular expression captures the following for instance:
+ // StatusBar in StatusBar#0
+ // com.appname in com.appname/com.appname.activity#0
+ // com.appname in SurfaceView - com.appname/com.appname.activity#0
+ const std::regex re("(?:SurfaceView[-\\s\\t]+)?([^/]+).*#\\d+");
+ std::smatch match;
+ if (std::regex_match(layerName.begin(), layerName.end(), match, re)) {
+ // There must be a match for group 1 otherwise the whole string is not
+ // matched and the above will return false
+ return match[1];
+ }
+ return "";
+}
+
void TimeStats::flushAvailableRecordsToStatsLocked(const std::string& layerName) {
ATRACE_CALL();
LayerRecord& layerRecord = timeStatsTracker[layerName];
TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
- std::vector<TimeRecord>& timeRecords = layerRecord.timeRecords;
+ std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
while (!timeRecords.empty()) {
if (!recordReadyLocked(layerName, &timeRecords[0])) break;
ALOGV("[%s]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerName.c_str(),
@@ -161,6 +177,7 @@
if (prevTimeRecord.ready) {
if (!timeStats.stats.count(layerName)) {
timeStats.stats[layerName].layerName = layerName;
+ timeStats.stats[layerName].packageName = getPackageName(layerName);
timeStats.stats[layerName].statsStart = static_cast<int64_t>(std::time(0));
}
TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timeStats.stats[layerName];
@@ -199,8 +216,7 @@
timeStats.stats[layerName].statsEnd = static_cast<int64_t>(std::time(0));
}
prevTimeRecord = timeRecords[0];
- // TODO(zzyiwei): change timeRecords to use std::deque
- timeRecords.erase(timeRecords.begin());
+ timeRecords.pop_front();
layerRecord.waitData--;
}
}
@@ -434,7 +450,6 @@
std::lock_guard<std::mutex> lock(mMutex);
ALOGD("Cleared");
- timeStats.dumpStats.clear();
timeStats.stats.clear();
timeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
timeStats.statsEnd = 0;
@@ -447,7 +462,7 @@
return mEnabled.load();
}
-void TimeStats::dump(bool asProto, uint32_t maxLayers, String8& result) {
+void TimeStats::dump(bool asProto, std::optional<uint32_t> maxLayers, String8& result) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
@@ -457,39 +472,15 @@
timeStats.statsEnd = static_cast<int64_t>(std::time(0));
- // TODO(zzyiwei): refactor dumpStats into TimeStatsHelper
- timeStats.dumpStats.clear();
- for (auto& ele : timeStats.stats) {
- timeStats.dumpStats.push_back(&ele.second);
- }
-
- std::sort(timeStats.dumpStats.begin(), timeStats.dumpStats.end(),
- [](TimeStatsHelper::TimeStatsLayer* const& l,
- TimeStatsHelper::TimeStatsLayer* const& r) {
- return l->totalFrames > r->totalFrames;
- });
-
- if (maxLayers != 0 && maxLayers < timeStats.dumpStats.size()) {
- timeStats.dumpStats.resize(maxLayers);
- }
-
if (asProto) {
- dumpAsProtoLocked(result);
+ ALOGD("Dumping TimeStats as proto");
+ SFTimeStatsGlobalProto timeStatsProto = timeStats.toProto(maxLayers);
+ result.append(timeStatsProto.SerializeAsString().c_str(), timeStatsProto.ByteSize());
} else {
- dumpAsTextLocked(result);
+ ALOGD("Dumping TimeStats as text");
+ result.append(timeStats.toString(maxLayers).c_str());
+ result.append("\n");
}
}
-void TimeStats::dumpAsTextLocked(String8& result) {
- ALOGD("Dumping TimeStats as text");
- result.append(timeStats.toString().c_str());
- result.append("\n");
-}
-
-void TimeStats::dumpAsProtoLocked(String8& result) {
- ALOGD("Dumping TimeStats as proto");
- SFTimeStatsGlobalProto timeStatsProto = timeStats.toProto();
- result.append(timeStatsProto.SerializeAsString().c_str(), timeStatsProto.ByteSize());
-}
-
} // namespace android
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index f76a62e..8318210 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -25,9 +25,10 @@
#include <utils/String8.h>
#include <utils/Vector.h>
+#include <deque>
#include <mutex>
+#include <optional>
#include <unordered_map>
-#include <vector>
using namespace android::surfaceflinger;
@@ -57,7 +58,7 @@
// fences to signal, but rather waiting to receive those fences/timestamps.
int32_t waitData = -1;
TimeRecord prevTimeRecord;
- std::vector<TimeRecord> timeRecords;
+ std::deque<TimeRecord> timeRecords;
};
public:
@@ -90,9 +91,7 @@
void disable();
void clear();
bool isEnabled();
- void dump(bool asProto, uint32_t maxLayer, String8& result);
- void dumpAsTextLocked(String8& result);
- void dumpAsProtoLocked(String8& result);
+ void dump(bool asProto, std::optional<uint32_t> maxLayers, String8& result);
std::atomic<bool> mEnabled = false;
std::mutex mMutex;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
index 66aa719..bef6b7c 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
@@ -1,6 +1,5 @@
cc_library_shared {
name: "libtimestats_proto",
- vendor_available: true,
export_include_dirs: ["include"],
srcs: [
@@ -9,11 +8,8 @@
],
shared_libs: [
- "android.hardware.graphics.common@1.1",
- "libui",
- "libprotobuf-cpp-lite",
"libbase",
- "liblog",
+ "libprotobuf-cpp-lite",
],
proto: {
@@ -21,35 +17,17 @@
},
cppflags: [
+ "-std=c++1z",
"-Werror",
- "-Wno-unused-parameter",
- "-Wno-format",
"-Wno-c++98-compat-pedantic",
- "-Wno-float-conversion",
"-Wno-disabled-macro-expansion",
+ "-Wno-float-conversion",
"-Wno-float-equal",
- "-Wno-sign-conversion",
- "-Wno-padded",
+ "-Wno-format",
"-Wno-old-style-cast",
+ "-Wno-padded",
+ "-Wno-sign-conversion",
"-Wno-undef",
+ "-Wno-unused-parameter",
],
-
-}
-
-java_library_static {
- name: "timestatsprotosnano",
- host_supported: true,
- proto: {
- type: "nano",
- },
- srcs: ["*.proto"],
- no_framework_libs: true,
- target: {
- android: {
- jarjar_rules: "jarjar-rules.txt",
- },
- host: {
- static_libs: ["libprotobuf-java-nano"],
- },
- },
}
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 3e5007c..21f3ef3 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -17,7 +17,6 @@
#include <timestatsproto/TimeStatsHelper.h>
#include <array>
-#include <regex>
#define HISTOGRAM_SIZE 85
@@ -47,55 +46,39 @@
hist[*iter]++;
}
-float TimeStatsHelper::Histogram::averageTime() {
+float TimeStatsHelper::Histogram::averageTime() const {
int64_t ret = 0;
int64_t count = 0;
- for (auto ele : hist) {
+ for (auto& ele : hist) {
count += ele.second;
ret += ele.first * ele.second;
}
return static_cast<float>(ret) / count;
}
-std::string TimeStatsHelper::Histogram::toString() {
+std::string TimeStatsHelper::Histogram::toString() const {
std::string result;
for (int32_t i = 0; i < HISTOGRAM_SIZE; ++i) {
int32_t bucket = histogramConfig[i];
- int32_t count = (hist.count(bucket) == 0) ? 0 : hist[bucket];
+ int32_t count = (hist.count(bucket) == 0) ? 0 : hist.at(bucket);
StringAppendF(&result, "%dms=%d ", bucket, count);
}
result.back() = '\n';
return result;
}
-static std::string getPackageName(const std::string& layerName) {
- // This regular expression captures the following for instance:
- // StatusBar in StatusBar#0
- // com.appname in com.appname/com.appname.activity#0
- // com.appname in SurfaceView - com.appname/com.appname.activity#0
- const std::regex re("(?:SurfaceView[-\\s\\t]+)?([^/]+).*#\\d+");
- std::smatch match;
- if (std::regex_match(layerName.begin(), layerName.end(), match, re)) {
- // There must be a match for group 1 otherwise the whole string is not
- // matched and the above will return false
- return match[1];
- }
- return "";
-}
-
-std::string TimeStatsHelper::TimeStatsLayer::toString() {
+std::string TimeStatsHelper::TimeStatsLayer::toString() const {
std::string result = "";
StringAppendF(&result, "layerName = %s\n", layerName.c_str());
- packageName = getPackageName(layerName);
StringAppendF(&result, "packageName = %s\n", packageName.c_str());
StringAppendF(&result, "statsStart = %lld\n", static_cast<long long int>(statsStart));
StringAppendF(&result, "statsEnd = %lld\n", static_cast<long long int>(statsEnd));
StringAppendF(&result, "totalFrames= %d\n", totalFrames);
- if (deltas.find("present2present") != deltas.end()) {
- StringAppendF(&result, "averageFPS = %.3f\n",
- 1000.0 / deltas["present2present"].averageTime());
+ auto iter = deltas.find("present2present");
+ if (iter != deltas.end()) {
+ StringAppendF(&result, "averageFPS = %.3f\n", 1000.0 / iter->second.averageTime());
}
- for (auto ele : deltas) {
+ for (auto& ele : deltas) {
StringAppendF(&result, "%s histogram is as below:\n", ele.first.c_str());
StringAppendF(&result, "%s", ele.second.toString().c_str());
}
@@ -103,7 +86,7 @@
return result;
}
-std::string TimeStatsHelper::TimeStatsGlobal::toString() {
+std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional<uint32_t> maxLayers) const {
std::string result = "SurfaceFlinger TimeStats:\n";
StringAppendF(&result, "statsStart = %lld\n", static_cast<long long int>(statsStart));
StringAppendF(&result, "statsEnd = %lld\n", static_cast<long long int>(statsEnd));
@@ -111,25 +94,25 @@
StringAppendF(&result, "missedFrames= %d\n", missedFrames);
StringAppendF(&result, "clientCompositionFrames= %d\n", clientCompositionFrames);
StringAppendF(&result, "TimeStats for each layer is as below:\n");
- for (auto ele : dumpStats) {
+ const auto dumpStats = generateDumpStats(maxLayers);
+ for (auto& ele : dumpStats) {
StringAppendF(&result, "%s", ele->toString().c_str());
}
return result;
}
-SFTimeStatsLayerProto TimeStatsHelper::TimeStatsLayer::toProto() {
+SFTimeStatsLayerProto TimeStatsHelper::TimeStatsLayer::toProto() const {
SFTimeStatsLayerProto layerProto;
layerProto.set_layer_name(layerName);
- packageName = getPackageName(layerName);
layerProto.set_package_name(packageName);
layerProto.set_stats_start(statsStart);
layerProto.set_stats_end(statsEnd);
layerProto.set_total_frames(totalFrames);
- for (auto ele : deltas) {
+ for (auto& ele : deltas) {
SFTimeStatsDeltaProto* deltaProto = layerProto.add_deltas();
deltaProto->set_delta_name(ele.first);
- for (auto histEle : ele.second.hist) {
+ for (auto& histEle : ele.second.hist) {
SFTimeStatsHistogramBucketProto* histProto = deltaProto->add_histograms();
histProto->set_render_millis(histEle.first);
histProto->set_frame_count(histEle.second);
@@ -138,19 +121,40 @@
return layerProto;
}
-SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto() {
+SFTimeStatsGlobalProto TimeStatsHelper::TimeStatsGlobal::toProto(
+ std::optional<uint32_t> maxLayers) const {
SFTimeStatsGlobalProto globalProto;
globalProto.set_stats_start(statsStart);
globalProto.set_stats_end(statsEnd);
globalProto.set_total_frames(totalFrames);
globalProto.set_missed_frames(missedFrames);
globalProto.set_client_composition_frames(clientCompositionFrames);
- for (auto ele : dumpStats) {
+ const auto dumpStats = generateDumpStats(maxLayers);
+ for (auto& ele : dumpStats) {
SFTimeStatsLayerProto* layerProto = globalProto.add_stats();
layerProto->CopyFrom(ele->toProto());
}
return globalProto;
}
+std::vector<TimeStatsHelper::TimeStatsLayer const*>
+TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional<uint32_t> maxLayers) const {
+ std::vector<TimeStatsLayer const*> dumpStats;
+ for (auto& ele : stats) {
+ dumpStats.push_back(&ele.second);
+ }
+
+ std::sort(dumpStats.begin(), dumpStats.end(),
+ [](TimeStatsHelper::TimeStatsLayer const* l,
+ TimeStatsHelper::TimeStatsLayer const* r) {
+ return l->totalFrames > r->totalFrames;
+ });
+
+ if (maxLayers && (*maxLayers < dumpStats.size())) {
+ dumpStats.resize(*maxLayers);
+ }
+ return dumpStats;
+}
+
} // namespace surfaceflinger
} // namespace android
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index c876f21..1798555 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -17,9 +17,7 @@
#include <timestatsproto/TimeStatsProtoHeader.h>
-#include <math/vec4.h>
-
-#include <memory>
+#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
@@ -36,8 +34,8 @@
std::unordered_map<int32_t, int32_t> hist;
void insert(int32_t delta);
- float averageTime();
- std::string toString();
+ float averageTime() const;
+ std::string toString() const;
};
class TimeStatsLayer {
@@ -49,8 +47,8 @@
int32_t totalFrames = 0;
std::unordered_map<std::string, Histogram> deltas;
- std::string toString();
- SFTimeStatsLayerProto toProto();
+ std::string toString() const;
+ SFTimeStatsLayerProto toProto() const;
};
class TimeStatsGlobal {
@@ -61,10 +59,13 @@
int32_t missedFrames = 0;
int32_t clientCompositionFrames = 0;
std::unordered_map<std::string, TimeStatsLayer> stats;
- std::vector<TimeStatsLayer*> dumpStats;
- std::string toString();
- SFTimeStatsGlobalProto toProto();
+ std::string toString(std::optional<uint32_t> maxLayers) const;
+ SFTimeStatsGlobalProto toProto(std::optional<uint32_t> maxLayers) const;
+
+ private:
+ std::vector<TimeStatsLayer const*> generateDumpStats(
+ std::optional<uint32_t> maxLayers) const;
};
};
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/jarjar-rules.txt b/services/surfaceflinger/TimeStats/timestatsproto/jarjar-rules.txt
deleted file mode 100644
index 40043a8..0000000
--- a/services/surfaceflinger/TimeStats/timestatsproto/jarjar-rules.txt
+++ /dev/null
@@ -1 +0,0 @@
-rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
index a8f6fa8..f29fbd1 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
+++ b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
@@ -20,10 +20,6 @@
option optimize_for = LITE_RUNTIME;
-// frameworks/base/core/proto/android/service/sftimestats.proto is based on
-// this proto. Please only make valid protobuf changes to these messages, and
-// keep the other file in sync with this one.
-
message SFTimeStatsGlobalProto {
// The start & end timestamps in UTC as
// milliseconds since January 1, 1970
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 6fb3351..c42e811 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -185,6 +185,7 @@
struct Surface {
android::sp<ANativeWindow> window;
VkSwapchainKHR swapchain_handle;
+ uint64_t consumer_usage;
};
VkSurfaceKHR HandleFromSurface(Surface* surface) {
@@ -496,9 +497,18 @@
surface->window = pCreateInfo->window;
surface->swapchain_handle = VK_NULL_HANDLE;
+ int err = native_window_get_consumer_usage(surface->window.get(),
+ &surface->consumer_usage);
+ if (err != android::NO_ERROR) {
+ ALOGE("native_window_get_consumer_usage() failed: %s (%d)",
+ strerror(-err), err);
+ surface->~Surface();
+ allocator->pfnFree(allocator->pUserData, surface);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
// TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
- int err =
+ err =
native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL);
if (err != 0) {
// TODO(jessehall): Improve error reporting. Can we enumerate possible
@@ -536,9 +546,45 @@
VKAPI_ATTR
VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/,
uint32_t /*queue_family*/,
- VkSurfaceKHR /*surface*/,
+ VkSurfaceKHR surface_handle,
VkBool32* supported) {
- *supported = VK_TRUE;
+ const Surface* surface = SurfaceFromHandle(surface_handle);
+ if (!surface) {
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ const ANativeWindow* window = surface->window.get();
+
+ int query_value;
+ int err = window->query(window, NATIVE_WINDOW_FORMAT, &query_value);
+ if (err != 0 || query_value < 0) {
+ ALOGE("NATIVE_WINDOW_FORMAT query failed: %s (%d) value=%d",
+ strerror(-err), err, query_value);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+
+ android_pixel_format native_format =
+ static_cast<android_pixel_format>(query_value);
+
+ bool format_supported = false;
+ switch (native_format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ format_supported = true;
+ break;
+ default:
+ break;
+ }
+
+ // USAGE_CPU_READ_MASK 0xFUL
+ // USAGE_CPU_WRITE_MASK (0xFUL << 4)
+ // The currently used bits are as below:
+ // USAGE_CPU_READ_RARELY = 2UL
+ // USAGE_CPU_READ_OFTEN = 3UL
+ // USAGE_CPU_WRITE_RARELY = (2UL << 4)
+ // USAGE_CPU_WRITE_OFTEN = (3UL << 4)
+ *supported = static_cast<VkBool32>(format_supported ||
+ (surface->consumer_usage & 0xFFUL) == 0);
+
return VK_SUCCESS;
}