Merge "surfaceflinger: fix per-frame metadata to be per-layer" into pi-dev
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 9648ede..80ef788 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -32,14 +32,20 @@
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
+
+#include <chrono>
+#include <functional>
+#include <future>
#include <memory>
#include <regex>
#include <set>
#include <string>
+#include <utility>
#include <vector>
#include <android-base/file.h>
#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
@@ -53,6 +59,7 @@
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
#include <serviceutils/PriorityDumper.h>
+#include <utils/StrongPointer.h>
#include "DumpstateInternal.h"
#include "DumpstateSectionReporter.h"
#include "DumpstateService.h"
@@ -1533,77 +1540,101 @@
printf("== Board\n");
printf("========================================================\n");
- ::android::sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
- if (dumpstate_device == nullptr) {
- MYLOGE("No IDumpstateDevice implementation\n");
- return;
- }
-
if (!IsZipping()) {
MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
return;
}
- std::string path[NUM_OF_DUMPS];
- android::base::unique_fd fd[NUM_OF_DUMPS];
- int numFds = 0;
-
+ std::vector<std::string> paths;
+ std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
for (int i = 0; i < NUM_OF_DUMPS; i++) {
- path[i] = kDumpstateBoardPath + kDumpstateBoardFiles[i];
- MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path[i].c_str());
+ paths.emplace_back(kDumpstateBoardPath + kDumpstateBoardFiles[i]);
+ remover.emplace_back(android::base::make_scope_guard(std::bind(
+ [](std::string path) {
+ if (remove(path.c_str()) != 0 && errno != ENOENT) {
+ MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
+ }
+ },
+ paths[i])));
+ }
- fd[i] = android::base::unique_fd(
- TEMP_FAILURE_RETRY(open(path[i].c_str(),
- O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
- if (fd[i] < 0) {
- MYLOGE("Could not open file %s: %s\n", path[i].c_str(), strerror(errno));
- return;
- } else {
- numFds++;
+ // Given that bugreport is required to diagnose failures, it's better to
+ // drop the result of IDumpstateDevice than to block the rest of bugreport
+ // for an arbitrary amount of time.
+ std::packaged_task<std::unique_ptr<ssize_t[]>()>
+ dumpstate_task([paths]() -> std::unique_ptr<ssize_t[]> {
+ ::android::sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
+ if (dumpstate_device == nullptr) {
+ MYLOGE("No IDumpstateDevice implementation\n");
+ return nullptr;
+ }
+
+ using ScopedNativeHandle =
+ std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
+ ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
+ [](native_handle_t* handle) {
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ });
+ if (handle == nullptr) {
+ MYLOGE("Could not create native_handle\n");
+ return nullptr;
+ }
+
+ for (size_t i = 0; i < paths.size(); i++) {
+ MYLOGI("Calling IDumpstateDevice implementation using path %s\n", paths[i].c_str());
+
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(
+ open(paths[i].c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+ if (fd < 0) {
+ MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
+ return nullptr;
+ }
+ handle.get()->data[i] = fd.release();
+ }
+
+ android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle.get());
+ if (!status.isOk()) {
+ MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
+ return nullptr;
+ }
+ auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
+ for (size_t i = 0; i < paths.size(); i++) {
+ struct stat s;
+ if (fstat(handle.get()->data[i], &s) == -1) {
+ MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
+ strerror(errno));
+ file_sizes[i] = -1;
+ continue;
+ }
+ file_sizes[i] = s.st_size;
+ }
+ return file_sizes;
+ });
+ auto result = dumpstate_task.get_future();
+ std::thread(std::move(dumpstate_task)).detach();
+ if (result.wait_for(10s) != std::future_status::ready) {
+ MYLOGE("dumpstateBoard timed out after 10s\n");
+ return;
+ }
+ std::unique_ptr<ssize_t[]> file_sizes = result.get();
+ if (file_sizes == nullptr) {
+ return;
+ }
+
+ for (size_t i = 0; i < paths.size(); i++) {
+ if (file_sizes[i] == -1) {
+ continue;
}
- }
-
- native_handle_t *handle = native_handle_create(numFds, 0);
- if (handle == nullptr) {
- MYLOGE("Could not create native_handle\n");
- return;
- }
-
- for (int i = 0; i < numFds; i++) {
- handle->data[i] = fd[i].release();
- }
-
- // TODO: need a timeout mechanism so dumpstate does not hang on device implementation call.
- android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle);
- if (!status.isOk()) {
- MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
- native_handle_close(handle);
- native_handle_delete(handle);
- return;
- }
-
- for (int i = 0; i < numFds; i++) {
- struct stat s;
- if (fstat(handle->data[i], &s) == -1) {
- MYLOGE("Failed to fstat %s: %d\n", kDumpstateBoardFiles[i].c_str(), errno);
- } else if (s.st_size > 0) {
- AddZipEntry(kDumpstateBoardFiles[i], path[i]);
- } else {
+ if (file_sizes[i] == 0) {
MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
+ continue;
}
+ AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
}
printf("*** See dumpstate-board.txt entry ***\n");
-
- native_handle_close(handle);
- native_handle_delete(handle);
-
- for (int i = 0; i < numFds; i++) {
- if (remove(path[i].c_str()) != 0) {
- MYLOGE("Could not remove(%s): %s\n", path[i].c_str(), strerror(errno));
- }
- }
}
static void ShowUsageAndExit(int exitCode = 1) {
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 788a6eb..885efec 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -984,7 +984,8 @@
}
if (mCurrentFence->isValid()) {
- if (SyncFeatures::getInstance().useWaitSync()) {
+ if (SyncFeatures::getInstance().useWaitSync() &&
+ SyncFeatures::getInstance().useNativeFenceSync()) {
// Create an EGLSyncKHR from the current fence.
int fenceFd = mCurrentFence->dup();
if (fenceFd == -1) {
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index d7d8618..58fed84 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -234,6 +234,33 @@
return android::base::StringPrintf("Unknown color mode %d", colorMode);
}
+std::string decodeColorTransform(android_color_transform colorTransform) {
+ switch (colorTransform) {
+ case HAL_COLOR_TRANSFORM_IDENTITY:
+ return std::string("Identity");
+
+ case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX:
+ return std::string("Arbitrary matrix");
+
+ case HAL_COLOR_TRANSFORM_VALUE_INVERSE:
+ return std::string("Inverse value");
+
+ case HAL_COLOR_TRANSFORM_GRAYSCALE:
+ return std::string("Grayscale");
+
+ case HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA:
+ return std::string("Correct protanopia");
+
+ case HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA:
+ return std::string("Correct deuteranopia");
+
+ case HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA:
+ return std::string("Correct tritanopia");
+ }
+
+ return android::base::StringPrintf("Unknown color transform %d", colorTransform);
+}
+
// Converts a PixelFormat to a human-readable string. Max 11 chars.
// (Could use a table of prefab String8 objects.)
std::string decodePixelFormat(android::PixelFormat format) {
diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h
index 6350d0c..5e5df43 100644
--- a/libs/ui/include/ui/DebugUtils.h
+++ b/libs/ui/include/ui/DebugUtils.h
@@ -30,5 +30,6 @@
std::string decodeRange(android_dataspace dataspace);
std::string dataspaceDetails(android_dataspace dataspace);
std::string decodeColorMode(android::ui::ColorMode colormode);
+std::string decodeColorTransform(android_color_transform colorTransform);
std::string decodePixelFormat(android::PixelFormat format);
std::string to_string(const android::Rect& rect);
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index b453d19..f3a9ad8 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -94,6 +94,7 @@
char const * const gExtensionString =
"EGL_KHR_image " // mandatory
"EGL_KHR_image_base " // mandatory
+ "EGL_KHR_image_gl_colorspace "
"EGL_KHR_image_pixmap "
"EGL_KHR_lock_surface "
"EGL_KHR_gl_colorspace "
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 2bd0a19..8e9e7fd 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -86,6 +86,7 @@
SensorService::SensorService()
: mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
mWakeLockAcquired(false) {
+ mUidPolicy = new UidPolicy(this);
}
bool SensorService::initializeHmacKey() {
@@ -283,7 +284,6 @@
enableSchedFifoMode();
// Start watching UID changes to apply policy.
- mUidPolicy = new UidPolicy(this);
mUidPolicy->registerSelf();
}
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index ba28eb5..ff994f5 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -105,6 +105,7 @@
"Layer.cpp",
"LayerProtoHelper.cpp",
"LayerRejecter.cpp",
+ "LayerStats.cpp",
"LayerVector.cpp",
"MessageQueue.cpp",
"MonitoredProducer.cpp",
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 93cb849..8281ce0 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -97,6 +97,7 @@
mPowerMode(initialPowerMode),
mActiveConfig(0),
mActiveColorMode(ColorMode::NATIVE),
+ mColorTransform(HAL_COLOR_TRANSFORM_IDENTITY),
mDisplayHasWideColor(supportWideColor),
mDisplayHasHdr(supportHdr)
{
@@ -267,6 +268,16 @@
return mActiveColorMode;
}
+void DisplayDevice::setColorTransform(const mat4& transform) {
+ const bool isIdentity = (transform == mat4());
+ mColorTransform =
+ isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
+}
+
+android_color_transform_t DisplayDevice::getColorTransform() const {
+ return mColorTransform;
+}
+
void DisplayDevice::setCompositionDataSpace(android_dataspace dataspace) {
ANativeWindow* const window = mNativeWindow.get();
native_window_set_buffers_data_space(window, dataspace);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index df729f5..31bb4d0 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -21,6 +21,8 @@
#include <stdlib.h>
+#include <math/mat4.h>
+
#include <ui/Region.h>
#include <binder/IBinder.h>
@@ -163,6 +165,8 @@
ui::ColorMode getActiveColorMode() const;
void setActiveColorMode(ui::ColorMode mode);
+ android_color_transform_t getColorTransform() const;
+ void setColorTransform(const mat4& transform);
void setCompositionDataSpace(android_dataspace dataspace);
/* ------------------------------------------------------------------------
@@ -237,6 +241,8 @@
int mActiveConfig;
// current active color mode
ui::ColorMode mActiveColorMode;
+ // Current color transform
+ android_color_transform_t mColorTransform;
// Need to know if display is wide-color capable or not.
// Initialized by SurfaceFlinger when the DisplayDevice is created.
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 98daec3..c2425ce 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -366,7 +366,6 @@
{
auto intError = mComposer.getColorModes(mId, outModes);
return static_cast<Error>(intError);
- return Error::None;
}
std::vector<std::shared_ptr<const Display::Config>> Display::getConfigs() const
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 166ac22..5c945ed 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -42,6 +42,7 @@
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
+#include "BufferLayer.h"
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "Layer.h"
@@ -635,6 +636,7 @@
hwcInfo.forceClientComposition = true;
} else {
auto transform = static_cast<HWC2::Transform>(orientation);
+ hwcInfo.transform = transform;
auto error = hwcLayer->setTransform(transform);
ALOGE_IF(error != HWC2::Error::None,
"[%s] Failed to set transform %s: "
@@ -1923,6 +1925,31 @@
layerInfo->set_app_id(state.appId);
}
+void Layer::writeToProto(LayerProto* layerInfo, int32_t hwcId) {
+ writeToProto(layerInfo, LayerVector::StateSet::Drawing);
+
+ const auto& hwcInfo = getBE().mHwcLayers.at(hwcId);
+
+ const Rect& frame = hwcInfo.displayFrame;
+ LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame());
+
+ const FloatRect& crop = hwcInfo.sourceCrop;
+ LayerProtoHelper::writeToProto(crop, layerInfo->mutable_hwc_crop());
+
+ const int32_t transform = static_cast<int32_t>(hwcInfo.transform);
+ layerInfo->set_hwc_transform(transform);
+
+ const int32_t compositionType = static_cast<int32_t>(hwcInfo.compositionType);
+ layerInfo->set_hwc_composition_type(compositionType);
+
+ if (std::strcmp(getTypeId(), "BufferLayer") == 0 &&
+ static_cast<BufferLayer*>(this)->isProtected()) {
+ layerInfo->set_is_protected(true);
+ } else {
+ layerInfo->set_is_protected(false);
+ }
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 9a9b5e6..69ffb20 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -113,7 +113,8 @@
layer(nullptr),
forceClientComposition(false),
compositionType(HWC2::Composition::Invalid),
- clearClientTarget(false) {}
+ clearClientTarget(false),
+ transform(HWC2::Transform::None) {}
HWComposer* hwc;
HWC2::Layer* layer;
@@ -123,6 +124,7 @@
Rect displayFrame;
FloatRect sourceCrop;
HWComposerBufferCache bufferCache;
+ HWC2::Transform transform;
};
// A layer can be attached to multiple displays when operating in mirror mode
@@ -357,6 +359,8 @@
void writeToProto(LayerProto* layerInfo,
LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
+ void writeToProto(LayerProto* layerInfo, int32_t hwcId);
+
protected:
/*
* onDraw - draws the surface.
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 6a33148..cc39550 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -37,6 +37,13 @@
rectProto->set_right(rect.right);
}
+void LayerProtoHelper::writeToProto(const FloatRect& rect, FloatRectProto* rectProto) {
+ rectProto->set_left(rect.left);
+ rectProto->set_top(rect.top);
+ rectProto->set_bottom(rect.bottom);
+ rectProto->set_right(rect.right);
+}
+
void LayerProtoHelper::writeToProto(const half4 color, ColorProto* colorProto) {
colorProto->set_r(color.r);
colorProto->set_g(color.g);
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 45a0b5d..860da63 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -29,6 +29,7 @@
class LayerProtoHelper {
public:
static void writeToProto(const Rect& rect, RectProto* rectProto);
+ static void writeToProto(const FloatRect& rect, FloatRectProto* rectProto);
static void writeToProto(const Region& region, RegionProto* regionProto);
static void writeToProto(const half4 color, ColorProto* colorProto);
static void writeToProto(const Transform& transform, TransformProto* transformProto);
@@ -36,4 +37,4 @@
};
} // namespace surfaceflinger
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
new file mode 100644
index 0000000..38ea6ed
--- /dev/null
+++ b/services/surfaceflinger/LayerStats.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#undef LOG_TAG
+#define LOG_TAG "LayerStats"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "LayerStats.h"
+#include "DisplayHardware/HWComposer.h"
+#include "ui/DebugUtils.h"
+
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+void LayerStats::enable() {
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mEnabled) return;
+ mLayerShapeStatsMap.clear();
+ mEnabled = true;
+ ALOGD("Logging enabled");
+}
+
+void LayerStats::disable() {
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mEnabled) return;
+ mEnabled = false;
+ ALOGD("Logging disabled");
+}
+
+void LayerStats::clear() {
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> lock(mMutex);
+ mLayerShapeStatsMap.clear();
+ ALOGD("Cleared current layer stats");
+}
+
+bool LayerStats::isEnabled() {
+ return mEnabled;
+}
+
+void LayerStats::traverseLayerTreeStatsLocked(
+ std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree,
+ const LayerProtoParser::LayerGlobal* layerGlobal, std::vector<std::string>& layerShapeVec) {
+ for (std::unique_ptr<LayerProtoParser::Layer>& layer : layerTree) {
+ if (!layer) continue;
+ traverseLayerTreeStatsLocked(std::move(layer->children), layerGlobal, layerShapeVec);
+ std::string key = "";
+ base::StringAppendF(&key, ",%s", layer->type.c_str());
+ base::StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
+ base::StringAppendF(&key, ",%d", layer->isProtected);
+ base::StringAppendF(&key, ",%s", layerTransform(layer->hwcTransform));
+ base::StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format));
+ base::StringAppendF(&key, ",%s", layer->dataspace.c_str());
+ base::StringAppendF(&key, ",%s",
+ destinationLocation(layer->hwcFrame.left, layerGlobal->resolution[0],
+ true));
+ base::StringAppendF(&key, ",%s",
+ destinationLocation(layer->hwcFrame.top, layerGlobal->resolution[1],
+ false));
+ base::StringAppendF(&key, ",%s",
+ destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
+ layerGlobal->resolution[0], true));
+ base::StringAppendF(&key, ",%s",
+ destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
+ layerGlobal->resolution[1], false));
+ base::StringAppendF(&key, ",%s", scaleRatioWH(layer.get()).c_str());
+ base::StringAppendF(&key, ",%s", alpha(static_cast<float>(layer->color.a)));
+
+ layerShapeVec.push_back(key);
+ ALOGV("%s", key.c_str());
+ }
+}
+
+void LayerStats::logLayerStats(const LayersProto& layersProto) {
+ ATRACE_CALL();
+ ALOGV("Logging");
+ auto layerGlobal = LayerProtoParser::generateLayerGlobalInfo(layersProto);
+ auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+ std::vector<std::string> layerShapeVec;
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ traverseLayerTreeStatsLocked(std::move(layerTree), &layerGlobal, layerShapeVec);
+
+ std::string layerShapeKey =
+ base::StringPrintf("%d,%s,%s,%s", static_cast<int32_t>(layerShapeVec.size()),
+ layerGlobal.colorMode.c_str(), layerGlobal.colorTransform.c_str(),
+ layerTransform(layerGlobal.globalTransform));
+ ALOGV("%s", layerShapeKey.c_str());
+
+ std::sort(layerShapeVec.begin(), layerShapeVec.end(), std::greater<std::string>());
+ for (auto const& s : layerShapeVec) {
+ layerShapeKey += s;
+ }
+
+ mLayerShapeStatsMap[layerShapeKey]++;
+}
+
+void LayerStats::dump(String8& result) {
+ ATRACE_CALL();
+ ALOGD("Dumping");
+ std::lock_guard<std::mutex> lock(mMutex);
+ result.append("Frequency,LayerCount,ColorMode,ColorTransform,Orientation\n");
+ result.append("LayerType,CompositionType,IsProtected,Transform,PixelFormat,Dataspace,");
+ result.append("DstX,DstY,DstWidth,DstHeight,WScale,HScale,Alpha\n");
+ for (auto& u : mLayerShapeStatsMap) {
+ result.appendFormat("%u,%s\n", u.second, u.first.c_str());
+ }
+}
+
+const char* LayerStats::destinationLocation(int32_t location, int32_t range, bool isHorizontal) {
+ static const char* locationArray[8] = {"0", "1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8"};
+ int32_t ratio = location * 8 / range;
+ if (ratio < 0) return "N/A";
+ if (isHorizontal) {
+ // X location is divided into 4 buckets {"0", "1/4", "1/2", "3/4"}
+ if (ratio > 6) return "3/4";
+ // use index 0, 2, 4, 6
+ return locationArray[ratio & ~1];
+ }
+ if (ratio > 7) return "7/8";
+ return locationArray[ratio];
+}
+
+const char* LayerStats::destinationSize(int32_t size, int32_t range, bool isWidth) {
+ static const char* sizeArray[8] = {"1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1"};
+ int32_t ratio = size * 8 / range;
+ if (ratio < 0) return "N/A";
+ if (isWidth) {
+ // width is divided into 4 buckets {"1/4", "1/2", "3/4", "1"}
+ if (ratio > 6) return "1";
+ // use index 1, 3, 5, 7
+ return sizeArray[ratio | 1];
+ }
+ if (ratio > 7) return "1";
+ return sizeArray[ratio];
+}
+
+const char* LayerStats::layerTransform(int32_t transform) {
+ return getTransformName(static_cast<hwc_transform_t>(transform));
+}
+
+const char* LayerStats::layerCompositionType(int32_t compositionType) {
+ return getCompositionName(static_cast<hwc2_composition_t>(compositionType));
+}
+
+const char* LayerStats::layerPixelFormat(int32_t pixelFormat) {
+ return decodePixelFormat(pixelFormat).c_str();
+}
+
+std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
+ if (!layer->type.compare("ColorLayer")) return "N/A,N/A";
+ std::string ret = "";
+ if (isRotated(layer->hwcTransform)) {
+ ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
+ static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
+ ret += ",";
+ ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
+ static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
+ } else {
+ ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
+ static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
+ ret += ",";
+ ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
+ static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
+ }
+ return ret;
+}
+
+const char* LayerStats::scaleRatio(int32_t destinationScale, int32_t sourceScale) {
+ // Make scale buckets from <1/64 to >= 16, to avoid floating point
+ // calculation, x64 on destinationScale first
+ int32_t scale = destinationScale * 64 / sourceScale;
+ if (!scale) return "<1/64";
+ if (scale < 2) return "1/64";
+ if (scale < 4) return "1/32";
+ if (scale < 8) return "1/16";
+ if (scale < 16) return "1/8";
+ if (scale < 32) return "1/4";
+ if (scale < 64) return "1/2";
+ if (scale < 128) return "1";
+ if (scale < 256) return "2";
+ if (scale < 512) return "4";
+ if (scale < 1024) return "8";
+ return ">=16";
+}
+
+const char* LayerStats::alpha(float a) {
+ if (a == 1.0f) return "1.0";
+ if (a > 0.9f) return "0.99";
+ if (a > 0.8f) return "0.9";
+ if (a > 0.7f) return "0.8";
+ if (a > 0.6f) return "0.7";
+ if (a > 0.5f) return "0.6";
+ if (a > 0.4f) return "0.5";
+ if (a > 0.3f) return "0.4";
+ if (a > 0.2f) return "0.3";
+ if (a > 0.1f) return "0.2";
+ if (a > 0.0f) return "0.1";
+ return "0.0";
+}
+
+bool LayerStats::isRotated(int32_t transform) {
+ return transform & HWC_TRANSFORM_ROT_90;
+}
+
+bool LayerStats::isVFlipped(int32_t transform) {
+ return transform & HWC_TRANSFORM_FLIP_V;
+}
+
+bool LayerStats::isHFlipped(int32_t transform) {
+ return transform & HWC_TRANSFORM_FLIP_H;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
new file mode 100644
index 0000000..7871fc6
--- /dev/null
+++ b/services/surfaceflinger/LayerStats.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2018 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 <layerproto/LayerProtoHeader.h>
+#include <layerproto/LayerProtoParser.h>
+#include <mutex>
+#include <unordered_map>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+class String8;
+
+class LayerStats {
+public:
+ void enable();
+ void disable();
+ void clear();
+ bool isEnabled();
+ void logLayerStats(const LayersProto& layersProto);
+ void dump(String8& result);
+
+private:
+ // Traverse layer tree to get all visible layers' stats
+ void traverseLayerTreeStatsLocked(
+ std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree,
+ const LayerProtoParser::LayerGlobal* layerGlobal,
+ std::vector<std::string>& layerShapeVec);
+ // Convert layer's top-left position into 8x8 percentage of the display
+ static const char* destinationLocation(int32_t location, int32_t range, bool isHorizontal);
+ // Convert layer's size into 8x8 percentage of the display
+ static const char* destinationSize(int32_t size, int32_t range, bool isWidth);
+ // Return the name of the transform
+ static const char* layerTransform(int32_t transform);
+ // Return the name of the composition type
+ static const char* layerCompositionType(int32_t compositionType);
+ // Return the name of the pixel format
+ static const char* layerPixelFormat(int32_t pixelFormat);
+ // Calculate scale ratios of layer's width/height with rotation information
+ static std::string scaleRatioWH(const LayerProtoParser::Layer* layer);
+ // Calculate scale ratio from source to destination and convert to string
+ static const char* scaleRatio(int32_t destinationScale, int32_t sourceScale);
+ // Bucket the alpha into designed buckets
+ static const char* alpha(float a);
+ // Return whether the original buffer is rotated in final composition
+ static bool isRotated(int32_t transform);
+ // Return whether the original buffer is V-flipped in final composition
+ static bool isVFlipped(int32_t transform);
+ // Return whether the original buffer is H-flipped in final composition
+ static bool isHFlipped(int32_t transform);
+
+ bool mEnabled = false;
+ // Protect mLayersStatsMap
+ std::mutex mMutex;
+ // Hashmap for tracking the frame(layer shape) stats
+ // KEY is a concatenation of all layers' properties within a frame
+ // VALUE is the number of times this particular set has been scanned out
+ std::unordered_map<std::string, uint32_t> mLayerShapeStatsMap;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f180a3b..f7f5b58 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1484,6 +1484,7 @@
setUpHWComposer();
doDebugFlashRegions();
doTracing("handleRefresh");
+ logLayerStats();
doComposition();
postComposition(refreshStartTime);
@@ -1553,6 +1554,25 @@
}
}
+void SurfaceFlinger::logLayerStats() {
+ ATRACE_CALL();
+ if (CC_UNLIKELY(mLayerStats.isEnabled())) {
+ int32_t hwcId = -1;
+ for (size_t dpy = 0; dpy < mDisplays.size(); ++dpy) {
+ const sp<const DisplayDevice>& displayDevice(mDisplays[dpy]);
+ if (displayDevice->isPrimary()) {
+ hwcId = displayDevice->getHwcDisplayId();
+ break;
+ }
+ }
+ if (hwcId < 0) {
+ ALOGE("LayerStats: Hmmm, no primary display?");
+ return;
+ }
+ mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(hwcId));
+ }
+}
+
void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
{
ATRACE_CALL();
@@ -1940,6 +1960,7 @@
continue;
}
if (colorMatrix != mPreviousColorMatrix) {
+ displayDevice->setColorTransform(colorMatrix);
status_t result = getBE().mHwc->setColorTransform(hwcId, colorMatrix);
ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
"display %zd: %d", displayId, result);
@@ -3772,6 +3793,34 @@
dumpWideColorInfo(result);
dumpAll = false;
}
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--enable-layer-stats"))) {
+ index++;
+ mLayerStats.enable();
+ dumpAll = false;
+ }
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--disable-layer-stats"))) {
+ index++;
+ mLayerStats.disable();
+ dumpAll = false;
+ }
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--clear-layer-stats"))) {
+ index++;
+ mLayerStats.clear();
+ dumpAll = false;
+ }
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--dump-layer-stats"))) {
+ index++;
+ mLayerStats.dump(result);
+ dumpAll = false;
+ }
}
if (dumpAll) {
@@ -3979,6 +4028,29 @@
return layersProto;
}
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(int32_t hwcId) const {
+ LayersProto layersProto;
+ const sp<DisplayDevice>& displayDevice(mDisplays[hwcId]);
+
+ SizeProto* resolution = layersProto.mutable_resolution();
+ resolution->set_w(displayDevice->getWidth());
+ resolution->set_h(displayDevice->getHeight());
+
+ layersProto.set_color_mode(decodeColorMode(displayDevice->getActiveColorMode()));
+ layersProto.set_color_transform(decodeColorTransform(displayDevice->getColorTransform()));
+ layersProto.set_global_transform(
+ static_cast<int32_t>(displayDevice->getOrientationTransform()));
+
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
+ if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(hwcId)) {
+ LayerProto* layerProto = layersProto.add_layers();
+ layer->writeToProto(layerProto, hwcId);
+ }
+ });
+
+ return layersProto;
+}
+
void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
String8& result) const
{
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 448509b..c7c3088 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -55,6 +55,7 @@
#include "DisplayDevice.h"
#include "DispSync.h"
#include "FrameTracker.h"
+#include "LayerStats.h"
#include "LayerVector.h"
#include "MessageQueue.h"
#include "SurfaceInterceptor.h"
@@ -645,6 +646,7 @@
void doComposition();
void doDebugFlashRegions();
void doTracing(const char* where);
+ void logLayerStats();
void doDisplayComposition(const sp<const DisplayDevice>& displayDevice, const Region& dirtyRegion);
// compose surfaces for display hw. this fails if using GL and the surface
@@ -711,6 +713,7 @@
void dumpBufferingStats(String8& result) const;
void dumpWideColorInfo(String8& result) const;
LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const;
+ LayersProto dumpVisibleLayersProtoInfo(int32_t hwcId) const;
bool isLayerTripleBufferingDisabled() const {
return this->mLayerTripleBufferingDisabled;
@@ -797,6 +800,7 @@
std::unique_ptr<SurfaceInterceptor> mInterceptor =
std::make_unique<impl::SurfaceInterceptor>(this);
SurfaceTracing mTracing;
+ LayerStats mLayerStats;
bool mUseHwcVirtualDisplays = false;
// Restrict layers to use two buffers in their bufferqueues.
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index 1383d28..fcf42f0 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -42,6 +42,16 @@
return sortLayers(lhs.get(), rhs.get());
}
+const LayerProtoParser::LayerGlobal LayerProtoParser::generateLayerGlobalInfo(
+ const LayersProto& layersProto) {
+ LayerGlobal layerGlobal;
+ layerGlobal.resolution = {layersProto.resolution().w(), layersProto.resolution().h()};
+ layerGlobal.colorMode = layersProto.color_mode();
+ layerGlobal.colorTransform = layersProto.color_transform();
+ layerGlobal.globalTransform = layersProto.global_transform();
+ return layerGlobal;
+}
+
std::vector<std::unique_ptr<LayerProtoParser::Layer>> LayerProtoParser::generateLayerTree(
const LayersProto& layersProto) {
std::unordered_map<int32_t, LayerProtoParser::Layer*> layerMap = generateMap(layersProto);
@@ -106,8 +116,13 @@
layer->activeBuffer = generateActiveBuffer(layerProto.active_buffer());
layer->queuedFrames = layerProto.queued_frames();
layer->refreshPending = layerProto.refresh_pending();
+ layer->hwcFrame = generateRect(layerProto.hwc_frame());
+ layer->hwcCrop = generateFloatRect(layerProto.hwc_crop());
+ layer->hwcTransform = layerProto.hwc_transform();
layer->windowType = layerProto.window_type();
layer->appId = layerProto.app_id();
+ layer->hwcCompositionType = layerProto.hwc_composition_type();
+ layer->isProtected = layerProto.is_protected();
return layer;
}
@@ -133,6 +148,16 @@
return rect;
}
+LayerProtoParser::FloatRect LayerProtoParser::generateFloatRect(const FloatRectProto& rectProto) {
+ LayerProtoParser::FloatRect rect;
+ rect.left = rectProto.left();
+ rect.top = rectProto.top();
+ rect.right = rectProto.right();
+ rect.bottom = rectProto.bottom();
+
+ return rect;
+}
+
LayerProtoParser::Transform LayerProtoParser::generateTransform(
const TransformProto& transformProto) {
LayerProtoParser::Transform transform;
@@ -246,6 +271,10 @@
return StringPrintf("[%3d, %3d, %3d, %3d]", left, top, right, bottom);
}
+std::string LayerProtoParser::FloatRect::to_string() const {
+ return StringPrintf("[%.2f, %.2f, %.2f, %.2f]", left, top, right, bottom);
+}
+
std::string LayerProtoParser::Region::to_string(const char* what) const {
std::string result =
StringPrintf(" Region %s (this=%lx count=%d)\n", what, static_cast<unsigned long>(id),
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index b56a6fb..74a6f28 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#include <layerproto/LayerProtoHeader.h>
@@ -57,6 +58,16 @@
std::string to_string() const;
};
+ class FloatRect {
+ public:
+ float left;
+ float top;
+ float right;
+ float bottom;
+
+ std::string to_string() const;
+ };
+
class Region {
public:
uint64_t id;
@@ -96,12 +107,26 @@
LayerProtoParser::ActiveBuffer activeBuffer;
int32_t queuedFrames;
bool refreshPending;
+ LayerProtoParser::Rect hwcFrame;
+ LayerProtoParser::FloatRect hwcCrop;
+ int32_t hwcTransform;
int32_t windowType;
int32_t appId;
+ int32_t hwcCompositionType;
+ bool isProtected;
std::string to_string() const;
};
+ class LayerGlobal {
+ public:
+ int2 resolution;
+ std::string colorMode;
+ std::string colorTransform;
+ int32_t globalTransform;
+ };
+
+ static const LayerGlobal generateLayerGlobalInfo(const LayersProto& layersProto);
static std::vector<std::unique_ptr<Layer>> generateLayerTree(const LayersProto& layersProto);
static std::string layersToString(std::vector<std::unique_ptr<LayerProtoParser::Layer>> layers);
@@ -110,6 +135,7 @@
static LayerProtoParser::Layer* generateLayer(const LayerProto& layerProto);
static LayerProtoParser::Region generateRegion(const RegionProto& regionProto);
static LayerProtoParser::Rect generateRect(const RectProto& rectProto);
+ static LayerProtoParser::FloatRect generateFloatRect(const FloatRectProto& rectProto);
static LayerProtoParser::Transform generateTransform(const TransformProto& transformProto);
static LayerProtoParser::ActiveBuffer generateActiveBuffer(
const ActiveBufferProto& activeBufferProto);
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index f18386b..77c6675 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -7,6 +7,10 @@
// Contains a list of all layers.
message LayersProto {
repeated LayerProto layers = 1;
+ optional SizeProto resolution = 2;
+ optional string color_mode = 3;
+ optional string color_transform = 4;
+ optional int32 global_transform = 5;
}
// Information about each layer.
@@ -64,8 +68,18 @@
// The number of frames available.
optional int32 queued_frames = 28;
optional bool refresh_pending = 29;
- optional int32 window_type = 30;
- optional int32 app_id = 31;
+ // The layer's composer backend destination frame
+ optional RectProto hwc_frame = 30;
+ // The layer's composer backend source crop
+ optional FloatRectProto hwc_crop = 31;
+ // The layer's composer backend transform
+ optional int32 hwc_transform = 32;
+ optional int32 window_type = 33;
+ optional int32 app_id = 34;
+ // The layer's composition type
+ optional int32 hwc_composition_type = 35;
+ // If it's a buffer layer, indicate if the content is protected
+ optional bool is_protected = 36;
}
message PositionProto {
@@ -97,6 +111,13 @@
optional int32 bottom = 4;
}
+message FloatRectProto {
+ optional float left = 1;
+ optional float top = 2;
+ optional float right = 3;
+ optional float bottom = 4;
+}
+
message ActiveBufferProto {
optional uint32 width = 1;
optional uint32 height = 2;
@@ -109,4 +130,4 @@
optional float g = 2;
optional float b = 3;
optional float a = 4;
-}
\ No newline at end of file
+}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index dec39e0..741fbb8 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -500,13 +500,36 @@
// both we and HAL can take part in
hook_extensions_.set(ext_bit);
break;
- case ProcHook::EXTENSION_UNKNOWN:
case ProcHook::KHR_get_physical_device_properties2:
- // HAL's extensions
+ case ProcHook::EXTENSION_UNKNOWN:
+ // Extensions we don't need to do anything about at this level
break;
- default:
- ALOGW("Ignored invalid instance extension %s", name);
+
+ case ProcHook::KHR_incremental_present:
+ case ProcHook::KHR_shared_presentable_image:
+ case ProcHook::KHR_swapchain:
+ case ProcHook::EXT_hdr_metadata:
+ case ProcHook::ANDROID_external_memory_android_hardware_buffer:
+ case ProcHook::ANDROID_native_buffer:
+ case ProcHook::GOOGLE_display_timing:
+ case ProcHook::EXTENSION_CORE:
+ case ProcHook::EXTENSION_COUNT:
+ // Device and meta extensions. If we ever get here it's a bug in
+ // our code. But enumerating them lets us avoid having a default
+ // case, and default hides other bugs.
+ ALOGE(
+ "CreateInfoWrapper::FilterExtension: invalid instance "
+ "extension '%s'. FIX ME",
+ name);
return;
+
+ // Don't use a default case. Without it, -Wswitch will tell us
+ // at compile time if someone adds a new ProcHook extension but
+ // doesn't handle it above. That's a real bug that has
+ // not-immediately-obvious effects.
+ //
+ // default:
+ // break;
}
} else {
switch (ext_bit) {
@@ -524,12 +547,36 @@
case ProcHook::EXT_hdr_metadata:
hook_extensions_.set(ext_bit);
break;
+ case ProcHook::ANDROID_external_memory_android_hardware_buffer:
case ProcHook::EXTENSION_UNKNOWN:
- // HAL's extensions
+ // Extensions we don't need to do anything about at this level
break;
- default:
- ALOGW("Ignored invalid device extension %s", name);
+
+ case ProcHook::KHR_android_surface:
+ case ProcHook::KHR_get_physical_device_properties2:
+ case ProcHook::KHR_get_surface_capabilities2:
+ case ProcHook::KHR_surface:
+ case ProcHook::EXT_debug_report:
+ case ProcHook::EXT_swapchain_colorspace:
+ case ProcHook::ANDROID_native_buffer:
+ case ProcHook::EXTENSION_CORE:
+ case ProcHook::EXTENSION_COUNT:
+ // Instance and meta extensions. If we ever get here it's a bug
+ // in our code. But enumerating them lets us avoid having a
+ // default case, and default hides other bugs.
+ ALOGE(
+ "CreateInfoWrapper::FilterExtension: invalid device "
+ "extension '%s'. FIX ME",
+ name);
return;
+
+ // Don't use a default case. Without it, -Wswitch will tell us
+ // at compile time if someone adds a new ProcHook extension but
+ // doesn't handle it above. That's a real bug that has
+ // not-immediately-obvious effects.
+ //
+ // default:
+ // break;
}
}