Merge "Set window to transparent when screenshotting layer." into pi-dev
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index bbff6fb..bcdd03e 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -33,7 +33,7 @@
#define TEST_APP_PRIVATE_DIR "/data/app-private/"
#define TEST_APP_EPHEMERAL_DIR "/data/app-ephemeral/"
#define TEST_ASEC_DIR "/mnt/asec/"
-#define TEST_EXPAND_DIR "/mnt/expand/"
+#define TEST_EXPAND_DIR "/mnt/expand/00000000-0000-0000-0000-000000000000/"
#define TEST_SYSTEM_DIR1 "/system/app/"
#define TEST_SYSTEM_DIR2 "/vendor/app/"
@@ -116,6 +116,41 @@
<< bad_path5 << " should be rejected as a invalid path";
}
+TEST_F(UtilsTest, IsValidApkPath_TopDir) {
+ EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/com.example"));
+ EXPECT_EQ(0, validate_apk_path(TEST_EXPAND_DIR "app/com.example"));
+ EXPECT_EQ(-1, validate_apk_path(TEST_DATA_DIR "data/com.example"));
+ EXPECT_EQ(-1, validate_apk_path(TEST_EXPAND_DIR "data/com.example"));
+}
+
+TEST_F(UtilsTest, IsValidApkPath_TopFile) {
+ EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/com.example/base.apk"));
+ EXPECT_EQ(0, validate_apk_path(TEST_EXPAND_DIR "app/com.example/base.apk"));
+ EXPECT_EQ(-1, validate_apk_path(TEST_DATA_DIR "data/com.example/base.apk"));
+ EXPECT_EQ(-1, validate_apk_path(TEST_EXPAND_DIR "data/com.example/base.apk"));
+}
+
+TEST_F(UtilsTest, IsValidApkPath_OatDir) {
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat"));
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat"));
+ EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat"));
+ EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat"));
+}
+
+TEST_F(UtilsTest, IsValidApkPath_OatDirDir) {
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat/arm64"));
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat/arm64"));
+ EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat/arm64"));
+ EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat/arm64"));
+}
+
+TEST_F(UtilsTest, IsValidApkPath_OatDirDirFile) {
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat/arm64/base.odex"));
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat/arm64/base.odex"));
+ EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat/arm64/base.odex"));
+ EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat/arm64/base.odex"));
+}
+
TEST_F(UtilsTest, IsValidApkPath_Private) {
// Internal directories
const char *private1 = TEST_APP_PRIVATE_DIR "example.apk";
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index a8c32ed..1ff45e4 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -855,21 +855,25 @@
* that path. Returns -1 when an invalid path is encountered and 0 when a valid path
* is encountered.
*/
-static int validate_apk_path_internal(const char *path, int maxSubdirs) {
- std::string path_ = path;
- if (validate_path(android_app_dir, path_, maxSubdirs) == 0) {
+static int validate_apk_path_internal(const std::string& path, int maxSubdirs) {
+ if (validate_path(android_app_dir, path, maxSubdirs) == 0) {
return 0;
- } else if (validate_path(android_app_private_dir, path_, maxSubdirs) == 0) {
+ } else if (validate_path(android_app_private_dir, path, maxSubdirs) == 0) {
return 0;
- } else if (validate_path(android_app_ephemeral_dir, path_, maxSubdirs) == 0) {
+ } else if (validate_path(android_app_ephemeral_dir, path, maxSubdirs) == 0) {
return 0;
- } else if (validate_path(android_asec_dir, path_, maxSubdirs) == 0) {
+ } else if (validate_path(android_asec_dir, path, maxSubdirs) == 0) {
return 0;
- } else if (validate_path(android_mnt_expand_dir, path_, std::max(maxSubdirs, 2)) == 0) {
- return 0;
- } else {
- return -1;
+ } else if (android::base::StartsWith(path, android_mnt_expand_dir)) {
+ // Rewrite the path as if it were on internal storage, and test that
+ size_t end = path.find('/', android_mnt_expand_dir.size() + 1);
+ if (end != std::string::npos) {
+ auto modified = path;
+ modified.replace(0, end + 1, android_data_dir);
+ return validate_apk_path_internal(modified, maxSubdirs);
+ }
}
+ return -1;
}
int validate_apk_path(const char* path) {
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 8e393c0..ff22048 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -503,7 +503,7 @@
using namespace ::android::hidl::manager::V1_0;
using namespace ::android::hidl::base::V1_0;
using std::literals::chrono_literals::operator""s;
- auto ret = timeoutIPC(2s, manager, &IServiceManager::debugDump, [&] (const auto &infos) {
+ auto ret = timeoutIPC(10s, manager, &IServiceManager::debugDump, [&] (const auto &infos) {
std::map<std::string, TableEntry> entries;
for (const auto &info : infos) {
std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 2d196c1..cb542bf 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -433,6 +433,7 @@
mDataPos = pos;
mNextObjectHint = 0;
+ mObjectsSorted = false;
}
status_t Parcel::setDataCapacity(size_t size)
@@ -1469,6 +1470,59 @@
LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
}
+status_t Parcel::validateReadData(size_t upperBound) const
+{
+ // Don't allow non-object reads on object data
+ if (mObjectsSorted || mObjectsSize <= 1) {
+data_sorted:
+ // Expect to check only against the next object
+ if (mNextObjectHint < mObjectsSize && upperBound > mObjects[mNextObjectHint]) {
+ // For some reason the current read position is greater than the next object
+ // hint. Iterate until we find the right object
+ size_t nextObject = mNextObjectHint;
+ do {
+ if (mDataPos < mObjects[nextObject] + sizeof(flat_binder_object)) {
+ // Requested info overlaps with an object
+ ALOGE("Attempt to read from protected data in Parcel %p", this);
+ return PERMISSION_DENIED;
+ }
+ nextObject++;
+ } while (nextObject < mObjectsSize && upperBound > mObjects[nextObject]);
+ mNextObjectHint = nextObject;
+ }
+ return NO_ERROR;
+ }
+ // Quickly determine if mObjects is sorted.
+ binder_size_t* currObj = mObjects + mObjectsSize - 1;
+ binder_size_t* prevObj = currObj;
+ while (currObj > mObjects) {
+ prevObj--;
+ if(*prevObj > *currObj) {
+ goto data_unsorted;
+ }
+ currObj--;
+ }
+ mObjectsSorted = true;
+ goto data_sorted;
+
+data_unsorted:
+ // Insertion Sort mObjects
+ // Great for mostly sorted lists. If randomly sorted or reverse ordered mObjects become common,
+ // switch to std::sort(mObjects, mObjects + mObjectsSize);
+ for (binder_size_t* iter0 = mObjects + 1; iter0 < mObjects + mObjectsSize; iter0++) {
+ binder_size_t temp = *iter0;
+ binder_size_t* iter1 = iter0 - 1;
+ while (iter1 >= mObjects && *iter1 > temp) {
+ *(iter1 + 1) = *iter1;
+ iter1--;
+ }
+ *(iter1 + 1) = temp;
+ }
+ mNextObjectHint = 0;
+ mObjectsSorted = true;
+ goto data_sorted;
+}
+
status_t Parcel::read(void* outData, size_t len) const
{
if (len > INT32_MAX) {
@@ -1479,6 +1533,10 @@
if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
&& len <= pad_size(len)) {
+ if (mObjectsSize > 0) {
+ status_t err = validateReadData(mDataPos + pad_size(len));
+ if(err != NO_ERROR) return err;
+ }
memcpy(outData, mData+mDataPos, len);
mDataPos += pad_size(len);
ALOGV("read Setting data pos of %p to %zu", this, mDataPos);
@@ -1497,6 +1555,11 @@
if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
&& len <= pad_size(len)) {
+ if (mObjectsSize > 0) {
+ status_t err = validateReadData(mDataPos + pad_size(len));
+ if(err != NO_ERROR) return NULL;
+ }
+
const void* data = mData+mDataPos;
mDataPos += pad_size(len);
ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos);
@@ -1510,6 +1573,11 @@
COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
if ((mDataPos+sizeof(T)) <= mDataSize) {
+ if (mObjectsSize > 0) {
+ status_t err = validateReadData(mDataPos + sizeof(T));
+ if(err != NO_ERROR) return err;
+ }
+
const void* data = mData+mDataPos;
mDataPos += sizeof(T);
*pArg = *reinterpret_cast<const T*>(data);
@@ -2366,6 +2434,7 @@
mObjects = const_cast<binder_size_t*>(objects);
mObjectsSize = mObjectsCapacity = objectsCount;
mNextObjectHint = 0;
+ mObjectsSorted = false;
mOwner = relFunc;
mOwnerCookie = relCookie;
for (size_t i = 0; i < mObjectsSize; i++) {
@@ -2524,6 +2593,7 @@
mObjects = NULL;
mObjectsSize = mObjectsCapacity = 0;
mNextObjectHint = 0;
+ mObjectsSorted = false;
mHasFds = false;
mFdsKnown = true;
mAllowFds = true;
@@ -2610,6 +2680,7 @@
mDataCapacity = desired;
mObjectsSize = mObjectsCapacity = objectsSize;
mNextObjectHint = 0;
+ mObjectsSorted = false;
} else if (mData) {
if (objectsSize < mObjectsSize) {
@@ -2631,6 +2702,7 @@
}
mObjectsSize = objectsSize;
mNextObjectHint = 0;
+ mObjectsSorted = false;
}
// We own the data, so we can just do a realloc().
@@ -2703,6 +2775,7 @@
mObjectsSize = 0;
mObjectsCapacity = 0;
mNextObjectHint = 0;
+ mObjectsSorted = false;
mHasFds = false;
mFdsKnown = true;
mAllowFds = true;
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 5d36526..dede78f 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -417,6 +417,7 @@
void freeDataNoInit();
void initState();
void scanForFds() const;
+ status_t validateReadData(size_t len) const;
template<class T>
status_t readAligned(T *pArg) const;
@@ -463,6 +464,7 @@
size_t mObjectsSize;
size_t mObjectsCapacity;
mutable size_t mNextObjectHint;
+ mutable bool mObjectsSorted;
mutable bool mFdsKnown;
mutable bool mHasFds;
diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h
index 0d30614..13aa3e9 100644
--- a/libs/vr/libpdx/private/pdx/service.h
+++ b/libs/vr/libpdx/private/pdx/service.h
@@ -589,6 +589,14 @@
}
/*
+ * Return true if a channel with the given ID exists in the Channel map.
+ */
+ bool HasChannelId(int channel_id) const {
+ std::lock_guard<std::mutex> autolock(channels_mutex_);
+ return channels_.find(channel_id) != channels_.end();
+ }
+
+ /*
* Subclasses of Service may override this method to provide a text string
* describing the state of the service. This method is called by
* HandleSystemMessage in response to the standard
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index ef8cca3..34b3b0a 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -45,6 +45,14 @@
const int user_id = message.GetEffectiveUserId();
const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
+ // Check if the display_manager_ has a defunct channel.
+ if (display_manager_ && !HasChannelId(display_manager_->channel_id())) {
+ ALOGE("DisplayManagerService::OnChannelOpen: Found defunct channel %d with "
+ "no OnChannelClose, clearing prior display manager.",
+ display_manager_->channel_id());
+ display_manager_ = nullptr;
+ }
+
// Prevent more than one display manager from registering at a time or
// untrusted UIDs from connecting.
if (display_manager_ || !trusted) {
diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h
index 3ad39d9..e8d7515 100644
--- a/opengl/include/GLES2/gl2ext.h
+++ b/opengl/include/GLES2/gl2ext.h
@@ -3612,17 +3612,6 @@
#define GL_SHADER_BINARY_VIV 0x8FC4
#endif /* GL_VIV_shader_binary */
-/* Temporary hack to allow frameworks/base/libs/hwui/debug to build.
- * This function was removed from the Khronos version of the headers
- * (it is specified with the EXT prefix, not OES). */
-#ifndef GL_ANDROID_draw_elements_base_vertex_backwards_compatibility
-#define GL_ANDROID_draw_elements_base_vertex_backwards_compatibility 1
-typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glMultiDrawElementsBaseVertexOES (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
-#endif
-#endif /* GL_ANDROID_draw_elements_base_vertex_backwards_compatibility */
-
#ifdef __cplusplus
}
#endif
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 58a774b..d90ab1d 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -55,6 +55,7 @@
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
using android::ui::ColorMode;
+using android::ui::RenderIntent;
/*
* Initialize the display to the specified values.
@@ -75,8 +76,8 @@
std::unique_ptr<RE::Surface> renderSurface,
int displayWidth,
int displayHeight,
- bool supportWideColor,
- bool supportHdr,
+ bool hasWideColorGamut,
+ bool hasHdr10,
int initialPowerMode)
: lastCompositionHadVisibleLayers(false),
mFlinger(flinger),
@@ -98,8 +99,8 @@
mActiveConfig(0),
mActiveColorMode(ColorMode::NATIVE),
mColorTransform(HAL_COLOR_TRANSFORM_IDENTITY),
- mDisplayHasWideColor(supportWideColor),
- mDisplayHasHdr(supportHdr)
+ mHasWideColorGamut(hasWideColorGamut),
+ mHasHdr10(hasHdr10)
{
// clang-format on
@@ -268,6 +269,14 @@
return mActiveColorMode;
}
+RenderIntent DisplayDevice::getActiveRenderIntent() const {
+ return mActiveRenderIntent;
+}
+
+void DisplayDevice::setActiveRenderIntent(RenderIntent renderIntent) {
+ mActiveRenderIntent = renderIntent;
+}
+
void DisplayDevice::setColorTransform(const mat4& transform) {
const bool isIdentity = (transform == mat4());
mColorTransform =
@@ -279,10 +288,15 @@
}
void DisplayDevice::setCompositionDataSpace(ui::Dataspace dataspace) {
+ mCompositionDataSpace = dataspace;
ANativeWindow* const window = mNativeWindow.get();
native_window_set_buffers_data_space(window, static_cast<android_dataspace>(dataspace));
}
+ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
+ return mCompositionDataSpace;
+}
+
// ----------------------------------------------------------------------------
void DisplayDevice::setLayerStack(uint32_t stack) {
@@ -464,8 +478,8 @@
tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
auto const surface = static_cast<Surface*>(window);
ui::Dataspace dataspace = surface->getBuffersDataSpace();
- result.appendFormat(" wideColor=%d, hdr=%d, colorMode=%s, dataspace: %s (%d)\n",
- mDisplayHasWideColor, mDisplayHasHdr,
+ result.appendFormat(" wideColorGamut=%d, hdr10=%d, colorMode=%s, dataspace: %s (%d)\n",
+ mHasWideColorGamut, mHasHdr10,
decodeColorMode(mActiveColorMode).c_str(),
dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 61ce30c..b8a8906 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -84,8 +84,8 @@
std::unique_ptr<RE::Surface> renderSurface,
int displayWidth,
int displayHeight,
- bool supportWideColor,
- bool supportHdr,
+ bool hasWideColorGamut,
+ bool hasHdr10,
int initialPowerMode);
// clang-format on
@@ -135,8 +135,8 @@
// machine happy without actually queueing a buffer if nothing has changed
status_t beginFrame(bool mustRecompose) const;
status_t prepareFrame(HWComposer& hwc);
- bool getWideColorSupport() const { return mDisplayHasWideColor; }
- bool getHdrSupport() const { return mDisplayHasHdr; }
+ bool hasWideColorGamut() const { return mHasWideColorGamut; }
+ bool hasHdr10() const { return mHasHdr10; }
void swapBuffers(HWComposer& hwc) const;
@@ -165,9 +165,12 @@
ui::ColorMode getActiveColorMode() const;
void setActiveColorMode(ui::ColorMode mode);
+ ui::RenderIntent getActiveRenderIntent() const;
+ void setActiveRenderIntent(ui::RenderIntent renderIntent);
android_color_transform_t getColorTransform() const;
void setColorTransform(const mat4& transform);
void setCompositionDataSpace(ui::Dataspace dataspace);
+ ui::Dataspace getCompositionDataSpace() const;
/* ------------------------------------------------------------------------
* Display active config management.
@@ -241,14 +244,17 @@
int mActiveConfig;
// current active color mode
ui::ColorMode mActiveColorMode;
+ // Current active render intent.
+ ui::RenderIntent mActiveRenderIntent;
+ ui::Dataspace mCompositionDataSpace;
// 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.
// Fed to RenderEngine during composition.
- bool mDisplayHasWideColor;
- bool mDisplayHasHdr;
+ bool mHasWideColorGamut;
+ bool mHasHdr10;
};
struct DisplayDeviceState {
@@ -291,9 +297,9 @@
bool isSecure() const override { return mDevice->isSecure(); }
bool needsFiltering() const override { return mDevice->needsFiltering(); }
Rect getSourceCrop() const override { return mSourceCrop; }
- bool getWideColorSupport() const override { return mDevice->getWideColorSupport(); }
- ui::ColorMode getActiveColorMode() const override {
- return mDevice->getActiveColorMode();
+ bool getWideColorSupport() const override { return mDevice->hasWideColorGamut(); }
+ ui::Dataspace getDataSpace() const override {
+ return mDevice->getCompositionDataSpace();
}
private:
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 9d356d8..8c0050e 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1643,6 +1643,21 @@
return true;
}
+// Dataspace::UNKNOWN, Dataspace::SRGB, Dataspace::SRGB_LINEAR,
+// Dataspace::V0_SRGB and Dataspace::V0_SRGB_LINEAR are considered legacy
+// SRGB data space for now.
+// Note that Dataspace::V0_SRGB and Dataspace::V0_SRGB_LINEAR are not legacy
+// data space, however since framework doesn't distinguish them out of legacy
+// SRGB, we have to treat them as the same for now.
+bool Layer::isLegacySrgbDataSpace() const {
+ // TODO(lpy) b/77652630, need to figure out when UNKNOWN can be treated as SRGB.
+ return mDrawingState.dataSpace == ui::Dataspace::UNKNOWN ||
+ mDrawingState.dataSpace == ui::Dataspace::SRGB ||
+ mDrawingState.dataSpace == ui::Dataspace::SRGB_LINEAR ||
+ mDrawingState.dataSpace == ui::Dataspace::V0_SRGB ||
+ mDrawingState.dataSpace == ui::Dataspace::V0_SRGB_LINEAR;
+}
+
void Layer::setParent(const sp<Layer>& layer) {
mCurrentParent = layer;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8d2a048..d382a1a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -297,6 +297,13 @@
bool reparent(const sp<IBinder>& newParentHandle);
bool detachChildren();
+ // Before color management is introduced, contents on Android have to be
+ // desaturated in order to match what they appears like visually.
+ // With color management, these contents will appear desaturated, thus
+ // needed to be saturated so that they match what they are designed for
+ // visually. When returns true, legacy SRGB data space is passed to HWC.
+ bool isLegacySrgbDataSpace() const;
+
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
// one empty rect.
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
index 38ea6ed..04ab121 100644
--- a/services/surfaceflinger/LayerStats.cpp
+++ b/services/surfaceflinger/LayerStats.cpp
@@ -57,11 +57,12 @@
}
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) {
+ const std::vector<std::unique_ptr<LayerProtoParser::Layer>>& layerTree,
+ const LayerProtoParser::LayerGlobal& layerGlobal,
+ std::vector<std::string>* const outLayerShapeVec) {
+ for (const auto& layer : layerTree) {
if (!layer) continue;
- traverseLayerTreeStatsLocked(std::move(layer->children), layerGlobal, layerShapeVec);
+ traverseLayerTreeStatsLocked(layer->children, layerGlobal, outLayerShapeVec);
std::string key = "";
base::StringAppendF(&key, ",%s", layer->type.c_str());
base::StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
@@ -70,21 +71,21 @@
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],
+ destinationLocation(layer->hwcFrame.left, layerGlobal.resolution[0],
true));
base::StringAppendF(&key, ",%s",
- destinationLocation(layer->hwcFrame.top, layerGlobal->resolution[1],
+ destinationLocation(layer->hwcFrame.top, layerGlobal.resolution[1],
false));
base::StringAppendF(&key, ",%s",
destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
- layerGlobal->resolution[0], true));
+ layerGlobal.resolution[0], true));
base::StringAppendF(&key, ",%s",
destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
- layerGlobal->resolution[1], false));
+ 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);
+ outLayerShapeVec->push_back(key);
ALOGV("%s", key.c_str());
}
}
@@ -97,7 +98,7 @@
std::vector<std::string> layerShapeVec;
std::lock_guard<std::mutex> lock(mMutex);
- traverseLayerTreeStatsLocked(std::move(layerTree), &layerGlobal, layerShapeVec);
+ traverseLayerTreeStatsLocked(layerTree, layerGlobal, &layerShapeVec);
std::string layerShapeKey =
base::StringPrintf("%d,%s,%s,%s", static_cast<int32_t>(layerShapeVec.size()),
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
index 7871fc6..7a190fd 100644
--- a/services/surfaceflinger/LayerStats.h
+++ b/services/surfaceflinger/LayerStats.h
@@ -38,9 +38,9 @@
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);
+ const std::vector<std::unique_ptr<LayerProtoParser::Layer>>& layerTree,
+ const LayerProtoParser::LayerGlobal& layerGlobal,
+ std::vector<std::string>* const outLayerShapeVec);
// 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
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 62a3d5b..3630677 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -30,15 +30,14 @@
virtual bool isSecure() const = 0;
virtual bool needsFiltering() const = 0;
virtual Rect getSourceCrop() const = 0;
+ virtual bool getWideColorSupport() const = 0;
+ virtual ui::Dataspace getDataSpace() const = 0;
virtual void render(std::function<void()> drawLayers) { drawLayers(); }
int getReqHeight() const { return mReqHeight; };
int getReqWidth() const { return mReqWidth; };
Transform::orientation_flags getRotationFlags() const { return mRotationFlags; };
- virtual bool getWideColorSupport() const = 0;
- virtual ui::ColorMode getActiveColorMode() const = 0;
-
status_t updateDimensions();
CaptureFill getCaptureFill() const { return mCaptureFill; };
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 781a30c..dfde30b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -157,6 +157,31 @@
return std::string(value) == "true";
}
+DisplayColorSetting toDisplayColorSetting(int value) {
+ switch(value) {
+ case 0:
+ return DisplayColorSetting::MANAGED;
+ case 1:
+ return DisplayColorSetting::UNMANAGED;
+ case 2:
+ return DisplayColorSetting::ENHANCED;
+ default:
+ return DisplayColorSetting::MANAGED;
+ }
+}
+
+std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
+ switch(displayColorSetting) {
+ case DisplayColorSetting::MANAGED:
+ return std::string("Natural Mode");
+ case DisplayColorSetting::UNMANAGED:
+ return std::string("Saturated Mode");
+ case DisplayColorSetting::ENHANCED:
+ return std::string("Auto Color Mode");
+ }
+ return std::string("Unknown Display Color Setting");
+}
+
NativeWindowSurface::~NativeWindowSurface() = default;
namespace impl {
@@ -690,6 +715,9 @@
ALOGE("Run StartPropertySetThread failed!");
}
+ mLegacySrgbSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(HWC_DISPLAY_PRIMARY,
+ Dataspace::SRGB_LINEAR);
+
ALOGV("Done initializing");
}
@@ -697,14 +725,13 @@
char value[PROPERTY_VALUE_MAX];
property_get("persist.sys.sf.color_saturation", value, "1.0");
- mSaturation = atof(value);
- ALOGV("Saturation is set to %.2f", mSaturation);
+ mGlobalSaturationFactor = atof(value);
+ ALOGV("Saturation is set to %.2f", mGlobalSaturationFactor);
property_get("persist.sys.sf.native_mode", value, "0");
- mForceNativeColorMode = atoi(value) == 1;
- if (mForceNativeColorMode) {
- ALOGV("Forcing native color mode");
- }
+ mDisplayColorSetting = toDisplayColorSetting(atoi(value));
+ ALOGV("Display Color Setting is set to %s.",
+ decodeDisplayColorSetting(mDisplayColorSetting).c_str());
}
void SurfaceFlinger::startBootAnim() {
@@ -989,11 +1016,29 @@
}
void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw,
- ColorMode mode) {
+ ColorMode mode, Dataspace dataSpace) {
int32_t type = hw->getDisplayType();
ColorMode currentMode = hw->getActiveColorMode();
+ Dataspace currentDataSpace = hw->getCompositionDataSpace();
+ RenderIntent currentRenderIntent = hw->getActiveRenderIntent();
- if (mode == currentMode) {
+ // Natural Mode means it's color managed and the color must be right,
+ // thus we pick RenderIntent::COLORIMETRIC as render intent.
+ // Native Mode means the display is not color managed, and whichever
+ // render intent is picked doesn't matter, thus return
+ // RenderIntent::COLORIMETRIC as default here.
+ RenderIntent renderIntent = RenderIntent::COLORIMETRIC;
+
+ // In Auto Color Mode, we want to strech to panel color space, right now
+ // only the built-in display supports it.
+ if (mDisplayColorSetting == DisplayColorSetting::ENHANCED &&
+ mBuiltinDisplaySupportsEnhance &&
+ hw->getDisplayType() == DisplayDevice::DISPLAY_PRIMARY) {
+ renderIntent = RenderIntent::ENHANCE;
+ }
+
+ if (mode == currentMode && dataSpace == currentDataSpace &&
+ renderIntent == currentRenderIntent) {
return;
}
@@ -1002,11 +1047,15 @@
return;
}
- ALOGD("Set active color mode: %s (%d), type=%d", decodeColorMode(mode).c_str(), mode,
- hw->getDisplayType());
-
hw->setActiveColorMode(mode);
- getHwComposer().setActiveColorMode(type, mode, RenderIntent::COLORIMETRIC);
+ hw->setCompositionDataSpace(dataSpace);
+ hw->setActiveRenderIntent(renderIntent);
+ getHwComposer().setActiveColorMode(type, mode, renderIntent);
+
+ ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), type=%d",
+ decodeColorMode(mode).c_str(), mode,
+ decodeRenderIntent(renderIntent).c_str(), renderIntent,
+ hw->getDisplayType());
}
@@ -1037,7 +1086,7 @@
ALOGW("Attempt to set active color mode %s %d for virtual display",
decodeColorMode(mMode).c_str(), mMode);
} else {
- mFlinger.setActiveColorModeInternal(hw, mMode);
+ mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN);
}
return true;
}
@@ -1072,7 +1121,7 @@
std::unique_ptr<HdrCapabilities> capabilities =
getBE().mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId());
if (capabilities) {
- if (displayDevice->getWideColorSupport() && !displayDevice->getHdrSupport()) {
+ if (displayDevice->hasWideColorGamut() && !displayDevice->hasHdr10()) {
// insert HDR10 as we will force client composition for HDR10
// layers
std::vector<int32_t> types = capabilities->getSupportedHdrTypes();
@@ -1821,73 +1870,78 @@
}
mat4 SurfaceFlinger::computeSaturationMatrix() const {
- if (mSaturation == 1.0f) {
+ if (mGlobalSaturationFactor == 1.0f) {
return mat4();
}
// Rec.709 luma coefficients
float3 luminance{0.213f, 0.715f, 0.072f};
- luminance *= 1.0f - mSaturation;
+ luminance *= 1.0f - mGlobalSaturationFactor;
return mat4(
- vec4{luminance.r + mSaturation, luminance.r, luminance.r, 0.0f},
- vec4{luminance.g, luminance.g + mSaturation, luminance.g, 0.0f},
- vec4{luminance.b, luminance.b, luminance.b + mSaturation, 0.0f},
+ vec4{luminance.r + mGlobalSaturationFactor, luminance.r, luminance.r, 0.0f},
+ vec4{luminance.g, luminance.g + mGlobalSaturationFactor, luminance.g, 0.0f},
+ vec4{luminance.b, luminance.b, luminance.b + mGlobalSaturationFactor, 0.0f},
vec4{0.0f, 0.0f, 0.0f, 1.0f}
);
}
-// pickColorMode translates a given dataspace into the best available color mode.
-// Currently only support sRGB and Display-P3.
-ColorMode SurfaceFlinger::pickColorMode(Dataspace dataSpace) const {
- if (mForceNativeColorMode) {
- return ColorMode::NATIVE;
+// Returns a dataspace that fits all visible layers. The returned dataspace
+// can only be one of
+//
+// - Dataspace::V0_SRGB
+// - Dataspace::DISPLAY_P3
+// - Dataspace::V0_SCRGB_LINEAR
+// TODO(b/73825729) Add BT2020 data space.
+ui::Dataspace SurfaceFlinger::getBestDataspace(
+ const sp<const DisplayDevice>& displayDevice) const {
+ Dataspace bestDataspace = Dataspace::V0_SRGB;
+ for (const auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ switch (layer->getDataSpace()) {
+ case Dataspace::V0_SCRGB:
+ case Dataspace::V0_SCRGB_LINEAR:
+ // return immediately
+ return Dataspace::V0_SCRGB_LINEAR;
+ case Dataspace::BT2020_PQ:
+ case Dataspace::BT2020_ITU_PQ:
+ // Historically, HDR dataspaces are ignored by SurfaceFlinger. But
+ // since SurfaceFlinger simulates HDR support now, it should honor
+ // them unless there is also native support.
+ if (!displayDevice->hasHdr10()) {
+ return Dataspace::V0_SCRGB_LINEAR;
+ }
+ break;
+ case Dataspace::DISPLAY_P3:
+ bestDataspace = Dataspace::DISPLAY_P3;
+ break;
+ default:
+ break;
+ }
}
- switch (dataSpace) {
- // treat Unknown as regular SRGB buffer, since that's what the rest of the
- // system expects.
- case Dataspace::UNKNOWN:
- case Dataspace::SRGB:
- case Dataspace::V0_SRGB:
- return ColorMode::SRGB;
- break;
-
- case Dataspace::DISPLAY_P3:
- return ColorMode::DISPLAY_P3;
- break;
-
- default:
- // TODO (courtneygo): Do we want to assert an error here?
- ALOGE("No color mode mapping for %s (%#x)",
- dataspaceDetails(static_cast<android_dataspace>(dataSpace)).c_str(),
- dataSpace);
- return ColorMode::SRGB;
- break;
- }
+ return bestDataspace;
}
-Dataspace SurfaceFlinger::bestTargetDataSpace(
- Dataspace a, Dataspace b, bool hasHdr) const {
- // Only support sRGB and Display-P3 right now.
- if (a == Dataspace::DISPLAY_P3 || b == Dataspace::DISPLAY_P3) {
- return Dataspace::DISPLAY_P3;
- }
- if (a == Dataspace::V0_SCRGB_LINEAR || b == Dataspace::V0_SCRGB_LINEAR) {
- return Dataspace::DISPLAY_P3;
- }
- if (a == Dataspace::V0_SCRGB || b == Dataspace::V0_SCRGB) {
- return Dataspace::DISPLAY_P3;
- }
- if (!hasHdr) {
- if (a == Dataspace::BT2020_PQ || b == Dataspace::BT2020_PQ) {
- return Dataspace::DISPLAY_P3;
- }
- if (a == Dataspace::BT2020_ITU_PQ || b == Dataspace::BT2020_ITU_PQ) {
- return Dataspace::DISPLAY_P3;
- }
+// Pick the ColorMode / Dataspace for the display device.
+// TODO(b/73825729) Add BT2020 color mode.
+void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice,
+ ColorMode* outMode, Dataspace* outDataSpace) const {
+ if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) {
+ *outMode = ColorMode::NATIVE;
+ *outDataSpace = Dataspace::UNKNOWN;
+ return;
}
- return Dataspace::V0_SRGB;
+ switch (getBestDataspace(displayDevice)) {
+ case Dataspace::DISPLAY_P3:
+ case Dataspace::V0_SCRGB_LINEAR:
+ *outMode = ColorMode::DISPLAY_P3;
+ *outDataSpace = Dataspace::DISPLAY_P3;
+ break;
+ default:
+ *outMode = ColorMode::SRGB;
+ *outDataSpace = Dataspace::V0_SRGB;
+ break;
+ }
}
void SurfaceFlinger::setUpHWComposer() {
@@ -1970,7 +2024,7 @@
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
- !displayDevice->getHdrSupport()) {
+ !displayDevice->hasHdr10()) {
layer->forceClientComposition(hwcId);
}
@@ -1984,19 +2038,10 @@
}
if (hasWideColorDisplay) {
- ColorMode newColorMode;
- Dataspace newDataSpace = Dataspace::V0_SRGB;
-
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- newDataSpace = bestTargetDataSpace(layer->getDataSpace(), newDataSpace,
- displayDevice->getHdrSupport());
- ALOGV("layer: %s, dataspace: %s (%#x), newDataSpace: %s (%#x)",
- layer->getName().string(), dataspaceDetails(static_cast<android_dataspace>(layer->getDataSpace())).c_str(),
- layer->getDataSpace(), dataspaceDetails(static_cast<android_dataspace>(newDataSpace)).c_str(), newDataSpace);
- }
- newColorMode = pickColorMode(newDataSpace);
-
- setActiveColorModeInternal(displayDevice, newColorMode);
+ ColorMode colorMode;
+ Dataspace dataSpace;
+ pickColorMode(displayDevice, &colorMode, &dataSpace);
+ setActiveColorModeInternal(displayDevice, colorMode, dataSpace);
}
}
@@ -2204,29 +2249,40 @@
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
const wp<IBinder>& display, int hwcId, const DisplayDeviceState& state,
const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) {
- bool hasWideColorSupport = false;
+ bool hasWideColorGamut = false;
if (hasWideColorDisplay) {
- std::vector<ColorMode> modes = getHwComposer().getColorModes(state.type);
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
for (ColorMode colorMode : modes) {
switch (colorMode) {
case ColorMode::DISPLAY_P3:
case ColorMode::ADOBE_RGB:
case ColorMode::DCI_P3:
- hasWideColorSupport = true;
+ hasWideColorGamut = true;
break;
+ // TODO(lpy) Handle BT2020, BT2100_PQ and BT2100_HLG properly.
default:
break;
}
+
+ std::vector<RenderIntent> renderIntents = getHwComposer().getRenderIntents(hwcId,
+ colorMode);
+ if (state.type == DisplayDevice::DISPLAY_PRIMARY) {
+ for (auto intent : renderIntents) {
+ if (intent == RenderIntent::ENHANCE) {
+ mBuiltinDisplaySupportsEnhance = true;
+ break;
+ }
+ }
+ }
}
}
- bool hasHdrSupport = false;
- std::unique_ptr<HdrCapabilities> hdrCapabilities =
- getHwComposer().getHdrCapabilities(state.type);
+ bool hasHdr10 = false;
+ std::unique_ptr<HdrCapabilities> hdrCapabilities = getHwComposer().getHdrCapabilities(hwcId);
if (hdrCapabilities) {
const std::vector<int32_t> types = hdrCapabilities->getSupportedHdrTypes();
auto iter = std::find(types.cbegin(), types.cend(), HAL_HDR_HDR10);
- hasHdrSupport = iter != types.cend();
+ hasHdr10 = iter != types.cend();
}
auto nativeWindowSurface = mCreateNativeWindowSurface(producer);
@@ -2260,18 +2316,19 @@
sp<DisplayDevice> hw =
new DisplayDevice(this, state.type, hwcId, state.isSecure, display, nativeWindow,
dispSurface, std::move(renderSurface), displayWidth, displayHeight,
- hasWideColorSupport, hasHdrSupport, initialPowerMode);
+ hasWideColorGamut, hasHdr10, initialPowerMode);
if (maxFrameBufferAcquiredBuffers >= 3) {
nativeWindowSurface->preallocateBuffers();
}
ColorMode defaultColorMode = ColorMode::NATIVE;
- if (hasWideColorSupport) {
+ Dataspace defaultDataSpace = Dataspace::UNKNOWN;
+ if (hasWideColorGamut) {
defaultColorMode = ColorMode::SRGB;
+ defaultDataSpace = Dataspace::V0_SRGB;
}
- setActiveColorModeInternal(hw, defaultColorMode);
- hw->setCompositionDataSpace(Dataspace::UNKNOWN);
+ setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace);
hw->setLayerStack(state.layerStack);
hw->setProjection(state.orientation, state.viewport, state.frame);
hw->setDisplayName(state.displayName);
@@ -2822,23 +2879,27 @@
const Region bounds(displayDevice->bounds());
const DisplayRenderArea renderArea(displayDevice);
const auto hwcId = displayDevice->getHwcDisplayId();
+ const bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId);
+ const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId);
+ const bool skipClientColorTransform = getBE().mHwc->hasCapability(
+ HWC2::Capability::SkipClientColorTransform);
+ ATRACE_INT("hasClientComposition", hasClientComposition);
mat4 oldColorMatrix;
- const bool applyColorMatrix = !getBE().mHwc->hasDeviceComposition(hwcId) &&
- !getBE().mHwc->hasCapability(HWC2::Capability::SkipClientColorTransform);
+ mat4 legacySrgbSaturationMatrix = mLegacySrgbSaturationMatrix;
+ const bool applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
if (applyColorMatrix) {
- mat4 colorMatrix = mColorMatrix * mDaltonizer();
+ mat4 colorMatrix = mColorMatrix * computeSaturationMatrix() * mDaltonizer();
oldColorMatrix = getRenderEngine().setupColorTransform(colorMatrix);
+ legacySrgbSaturationMatrix = colorMatrix * legacySrgbSaturationMatrix;
}
- bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId);
if (hasClientComposition) {
ALOGV("hasClientComposition");
Dataspace outputDataspace = Dataspace::UNKNOWN;
- if (displayDevice->getWideColorSupport() &&
- displayDevice->getActiveColorMode() == ColorMode::DISPLAY_P3) {
- outputDataspace = Dataspace::DISPLAY_P3;
+ if (displayDevice->hasWideColorGamut()) {
+ outputDataspace = displayDevice->getCompositionDataSpace();
}
getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
@@ -2855,7 +2916,6 @@
}
// Never touch the framebuffer if we don't have any framebuffer layers
- const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId);
if (hasDeviceComposition) {
// when using overlays, we assume a fully transparent framebuffer
// NOTE: we could reduce how much we need to clear, for instance
@@ -2930,7 +2990,20 @@
break;
}
case HWC2::Composition::Client: {
+ // Only apply saturation matrix layer that is legacy SRGB dataspace
+ // when auto color mode is on.
+ bool restore = false;
+ mat4 savedMatrix;
+ if (mDisplayColorSetting == DisplayColorSetting::ENHANCED &&
+ layer->isLegacySrgbDataSpace()) {
+ savedMatrix =
+ getRenderEngine().setupColorTransform(legacySrgbSaturationMatrix);
+ restore = true;
+ }
layer->draw(renderArea, clip);
+ if (restore) {
+ getRenderEngine().setupColorTransform(savedMatrix);
+ }
break;
}
default:
@@ -4004,7 +4077,7 @@
void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
result.appendFormat("hasWideColorDisplay: %d\n", hasWideColorDisplay);
- result.appendFormat("forceNativeColorMode: %d\n", mForceNativeColorMode);
+ result.appendFormat("DisplayColorSetting: %d\n", mDisplayColorSetting);
// TODO: print out if wide-color mode is active or not
@@ -4500,15 +4573,22 @@
return NO_ERROR;
}
case 1022: { // Set saturation boost
- mSaturation = std::max(0.0f, std::min(data.readFloat(), 2.0f));
+ mGlobalSaturationFactor = std::max(0.0f, std::min(data.readFloat(), 2.0f));
invalidateHwcGeometry();
repaintEverything();
return NO_ERROR;
}
case 1023: { // Set native mode
- mForceNativeColorMode = data.readInt32() == 1;
+ int32_t value = data.readInt32();
+ if (value > 2) {
+ return BAD_VALUE;
+ }
+ if (value == 2 && !mBuiltinDisplaySupportsEnhance) {
+ return BAD_VALUE;
+ }
+ mDisplayColorSetting = toDisplayColorSetting(value);
invalidateHwcGeometry();
repaintEverything();
return NO_ERROR;
@@ -4535,6 +4615,23 @@
reply->writeBool(mTracing.isEnabled());
return NO_ERROR;
}
+ // Is a DisplayColorSetting supported?
+ case 1027: {
+ int32_t value = data.readInt32();
+ switch (value) {
+ case 0:
+ reply->writeBool(hasWideColorDisplay);
+ return NO_ERROR;
+ case 1:
+ reply->writeBool(true);
+ return NO_ERROR;
+ case 2:
+ reply->writeBool(mBuiltinDisplaySupportsEnhance);
+ return NO_ERROR;
+ default:
+ return BAD_VALUE;
+ }
+ }
}
}
return err;
@@ -4602,6 +4699,7 @@
mCrop(crop),
mFlinger(flinger),
mChildrenOnly(childrenOnly) {}
+ const Transform& getTransform() const override { return mTransform; }
Rect getBounds() const override {
const Layer::State& layerState(mLayer->getDrawingState());
return Rect(layerState.active.w, layerState.active.h);
@@ -4610,7 +4708,15 @@
int getWidth() const override { return mLayer->getDrawingState().active.w; }
bool isSecure() const override { return false; }
bool needsFiltering() const override { return false; }
- const Transform& getTransform() const { return mTransform; }
+ Rect getSourceCrop() const override {
+ if (mCrop.isEmpty()) {
+ return getBounds();
+ } else {
+ return mCrop;
+ }
+ }
+ bool getWideColorSupport() const override { return false; }
+ Dataspace getDataSpace() const override { return Dataspace::UNKNOWN; }
class ReparentForDrawing {
public:
@@ -4639,16 +4745,6 @@
}
}
- Rect getSourceCrop() const override {
- if (mCrop.isEmpty()) {
- return getBounds();
- } else {
- return mCrop;
- }
- }
- bool getWideColorSupport() const override { return false; }
- ColorMode getActiveColorMode() const override { return ColorMode::NATIVE; }
-
private:
const sp<Layer> mLayer;
const Rect mCrop;
@@ -4820,9 +4916,8 @@
}
Dataspace outputDataspace = Dataspace::UNKNOWN;
- if (renderArea.getWideColorSupport() &&
- renderArea.getActiveColorMode() == ColorMode::DISPLAY_P3) {
- outputDataspace = Dataspace::DISPLAY_P3;
+ if (renderArea.getWideColorSupport()) {
+ outputDataspace = renderArea.getDataSpace();
}
getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a29d1d7..14028ff 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -123,6 +123,12 @@
eTransactionMask = 0x0f,
};
+enum class DisplayColorSetting : int32_t {
+ MANAGED = 0,
+ UNMANAGED = 1,
+ ENHANCED = 2,
+};
+
// A thin interface to abstract creating instances of Surface (gui/Surface.h) to
// use as a NativeWindow.
class NativeWindowSurface {
@@ -467,7 +473,9 @@
bool stateLockHeld);
// Called on the main thread in response to setActiveColorMode()
- void setActiveColorModeInternal(const sp<DisplayDevice>& hw, ui::ColorMode colorMode);
+ void setActiveColorModeInternal(const sp<DisplayDevice>& hw,
+ ui::ColorMode colorMode,
+ ui::Dataspace dataSpace);
// Returns whether the transaction actually modified any state
bool handleMessageTransaction();
@@ -641,9 +649,10 @@
// Given a dataSpace, returns the appropriate color_mode to use
// to display that dataSpace.
- ui::ColorMode pickColorMode(ui::Dataspace dataSpace) const;
- ui::Dataspace bestTargetDataSpace(ui::Dataspace a, ui::Dataspace b,
- bool hasHdr) const;
+ ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& displayDevice) const;
+ void pickColorMode(const sp<DisplayDevice>& displayDevice,
+ ui::ColorMode* outMode,
+ ui::Dataspace* outDataSpace) const;
mat4 computeSaturationMatrix() const;
@@ -846,7 +855,6 @@
size_t mNumLayers;
-
// Verify that transaction is being called by an approved process:
// either AID_GRAPHICS or AID_SYSTEM.
status_t CheckTransactCodeCredentials(uint32_t code);
@@ -856,8 +864,12 @@
static bool useVrFlinger;
std::thread::id mMainThreadId;
- float mSaturation = 1.0f;
- bool mForceNativeColorMode = false;
+ DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::MANAGED;
+ // Applied on sRGB layers when the render intent is non-colorimetric.
+ mat4 mLegacySrgbSaturationMatrix;
+ // Applied globally.
+ float mGlobalSaturationFactor = 1.0f;
+ bool mBuiltinDisplaySupportsEnhance = false;
using CreateBufferQueueFunction =
std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 11ffc3f..4af47d2 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -251,20 +251,22 @@
bool VrHwc::hasCapability(hwc2_capability_t /* capability */) { return false; }
void VrHwc::registerEventCallback(EventCallback* callback) {
- event_callback_ = callback;
-
- if (client_ != nullptr) {
- {
- int32_t width, height;
- GetPrimaryDisplaySize(&width, &height);
- std::lock_guard<std::mutex> guard(mutex_);
- // Create the primary display late to avoid initialization issues between
- // VR HWC and SurfaceFlinger.
- displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
- }
- event_callback_->onHotplug(kDefaultDisplayId,
- IComposerCallback::Connection::CONNECTED);
+ {
+ std::lock_guard<std::mutex> guard(mutex_);
+ event_callback_ = callback;
+ int32_t width, height;
+ GetPrimaryDisplaySize(&width, &height);
+ // Create the primary display late to avoid initialization issues between
+ // VR HWC and SurfaceFlinger.
+ displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
}
+ event_callback_->onHotplug(kDefaultDisplayId,
+ IComposerCallback::Connection::CONNECTED);
+}
+
+void VrHwc::unregisterEventCallback() {
+ std::lock_guard<std::mutex> guard(mutex_);
+ event_callback_ = nullptr;
}
uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; }
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index d5d5f55..85e587a 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -213,7 +213,7 @@
std::string dumpDebugInfo() override { return {}; }
void registerEventCallback(EventCallback* callback) override;
- void unregisterEventCallback() override {}
+ void unregisterEventCallback() override;
uint32_t getMaxVirtualDisplayCount() override;
Error createVirtualDisplay(uint32_t width, uint32_t height,