Merge "Deprecate legacy and unused DVR API" into pi-dev
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 21d9ace..f65f4f8 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -105,7 +105,6 @@
{ "video", "Video", ATRACE_TAG_VIDEO, { } },
{ "camera", "Camera", ATRACE_TAG_CAMERA, { } },
{ "hal", "Hardware Modules", ATRACE_TAG_HAL, { } },
- { "app", "Application", ATRACE_TAG_APP, { } },
{ "res", "Resource Loading", ATRACE_TAG_RESOURCES, { } },
{ "dalvik", "Dalvik VM", ATRACE_TAG_DALVIK, { } },
{ "rs", "RenderScript", ATRACE_TAG_RS, { } },
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 833ffbf..860a68b 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -356,8 +356,8 @@
* Ensure that we have a hard-limit quota to protect against abusive apps;
* they should never use more than 90% of blocks or 50% of inodes.
*/
-static int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std::string& device,
- uid_t uid) {
+static int prepare_app_quota(const std::unique_ptr<std::string>& uuid ATTRIBUTE_UNUSED,
+ const std::string& device, uid_t uid) {
// Skip when reserved blocks are protecting us against abusive apps
if (android::base::GetBoolProperty(kPropHasReserved, false)) return 0;
// Skip when device no quotas present
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/installd/utils.h b/cmds/installd/utils.h
index b74073c..5829c4f 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -36,7 +36,7 @@
#define BYPASS_QUOTA 0
#define BYPASS_SDCARDFS 0
-#define APPLY_HARD_QUOTAS 1
+#define APPLY_HARD_QUOTAS 0
namespace android {
namespace installd {
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/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml
new file mode 100644
index 0000000..ffebc9f
--- /dev/null
+++ b/data/etc/go_handheld_core_hardware.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<!-- These are the hardware components that all Android Go handheld devices
+ must include. Devices with optional hardware must also include extra
+ hardware files, per the comments below.
+-->
+<permissions>
+ <!-- This is Android and fully CTS compatible. Basically this is for CTS tests to use. -->
+ <feature name="android.software.cts" />
+
+ <feature name="android.hardware.audio.output" />
+ <feature name="android.hardware.camera" />
+ <feature name="android.hardware.location" />
+ <feature name="android.hardware.location.network" />
+ <feature name="android.hardware.sensor.compass" />
+ <feature name="android.hardware.sensor.accelerometer" />
+ <feature name="android.hardware.bluetooth" />
+ <feature name="android.hardware.touchscreen" />
+ <feature name="android.hardware.microphone" />
+ <feature name="android.hardware.screen.portrait" />
+ <feature name="android.hardware.screen.landscape" />
+
+ <!-- basic system services -->
+ <feature name="android.software.connectionservice" />
+ <feature name="android.software.backup" />
+ <feature name="android.software.home_screen" />
+ <feature name="android.software.input_methods" />
+ <feature name="android.software.print" />
+ <feature name="android.software.companion_device_setup" />
+ <feature name="android.software.autofill" />
+
+ <!-- Feature to specify if the device supports adding device admins. -->
+ <feature name="android.software.device_admin" />
+
+ <!-- Devices with all optimizations required to support VR Mode and
+ pass all CDD requirements for this feature may include
+ android.hardware.vr.high_performance -->
+ <!-- Devices that support VR headtracking features and pass all CDD
+ requirements may include
+ android.hardware.vr.headtracking -->
+
+ <!-- devices with GPS must include android.hardware.location.gps.xml -->
+ <!-- devices with an autofocus camera and/or flash must include either
+ android.hardware.camera.autofocus.xml or
+ android.hardware.camera.autofocus-flash.xml -->
+ <!-- devices with a front facing camera must include
+ android.hardware.camera.front.xml -->
+ <!-- devices with WiFi must also include android.hardware.wifi.xml -->
+ <!-- devices that support multitouch must include the most appropriate one
+ of these files:
+
+ If only partial (non-independent) pointers are supported:
+ android.hardware.touchscreen.multitouch.xml
+
+ If up to 4 independently tracked pointers are supported:
+ include android.hardware.touchscreen.multitouch.distinct.xml
+
+ If 5 or more independently tracked pointers are supported:
+ include android.hardware.touchscreen.multitouch.jazzhand.xml
+
+ ONLY ONE of the above should be included. -->
+ <!-- devices with an ambient light sensor must also include
+ android.hardware.sensor.light.xml -->
+ <!-- devices with a proximity sensor must also include
+ android.hardware.sensor.proximity.xml -->
+ <!-- GSM phones must also include android.hardware.telephony.gsm.xml -->
+ <!-- CDMA phones must also include android.hardware.telephony.cdma.xml -->
+ <!-- Devices that have low-latency audio stacks suitable for apps like
+ VoIP may include android.hardware.audio.low_latency.xml. ONLY apps
+ that meet the requirements specified in the CDD may include this. -->
+</permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 6d739a1..c76e611 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -14,9 +14,9 @@
limitations under the License.
-->
-<!-- These are the hardware components that all handheld devices
- must include. Devices with optional hardware must also include extra
- hardware files, per the comments below.
+<!-- These are the hardware components that all handheld devices except Android Go
+ must include, for Android Go devices include go_handheld_core_hardware.xml.
+ Devices with optional hardware must also include extra hardware files, per the comments below.
Handheld devices include phones, mobile Internet devices (MIDs),
Personal Media Players (PMPs), small tablets (7" or less), and similar
diff --git a/headers/media_plugin/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h
index 67f4511..4de314d 100644
--- a/headers/media_plugin/media/cas/CasAPI.h
+++ b/headers/media_plugin/media/cas/CasAPI.h
@@ -63,7 +63,7 @@
// Construct a new instance of a CasPlugin given a CA_system_id
virtual status_t createPlugin(
int32_t CA_system_id,
- uint64_t appData,
+ void *appData,
CasPluginCallback callback,
CasPlugin **plugin) = 0;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index f739f07..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)
@@ -1276,7 +1277,7 @@
if (err) return err;
// payload
- void* const buf = this->writeInplace(pad_size(len));
+ void* const buf = this->writeInplace(len);
if (buf == NULL)
return BAD_VALUE;
@@ -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/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index bbf681e..63560c4 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -101,7 +101,8 @@
SurfaceComposerClient::Transaction::Transaction(const Transaction& other) :
mForceSynchronous(other.mForceSynchronous),
mTransactionNestCount(other.mTransactionNestCount),
- mAnimation(other.mAnimation) {
+ mAnimation(other.mAnimation),
+ mEarlyWakeup(other.mEarlyWakeup) {
mDisplayStates = other.mDisplayStates;
mComposerStates = other.mComposerStates;
}
@@ -157,9 +158,13 @@
if (mAnimation) {
flags |= ISurfaceComposer::eAnimation;
}
+ if (mEarlyWakeup) {
+ flags |= ISurfaceComposer::eEarlyWakeup;
+ }
mForceSynchronous = false;
mAnimation = false;
+ mEarlyWakeup = false;
sf->setTransactionState(composerStates, displayStates, flags);
mStatus = NO_ERROR;
@@ -185,6 +190,10 @@
mAnimation = true;
}
+void SurfaceComposerClient::Transaction::setEarlyWakeup() {
+ mEarlyWakeup = true;
+}
+
layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
if (mComposerStates.count(sc) == 0) {
// we don't have it, add an initialized layer_state to our list
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 3591090..e401572 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -61,6 +61,11 @@
enum {
eSynchronous = 0x01,
eAnimation = 0x02,
+
+ // Indicates that this transaction will likely result in a lot of layers being composed, and
+ // thus, SurfaceFlinger should wake-up earlier to avoid missing frame deadlines. In this
+ // case SurfaceFlinger will wake up at (sf vsync offset - debug.sf.early_phase_offset_ns)
+ eEarlyWakeup = 0x04
};
enum {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index ffc22f6..377fe68 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -154,6 +154,7 @@
uint32_t mForceSynchronous = 0;
uint32_t mTransactionNestCount = 0;
bool mAnimation = false;
+ bool mEarlyWakeup = false;
int mStatus = NO_ERROR;
@@ -273,6 +274,7 @@
const Rect& displayRect);
void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
void setAnimationTransaction();
+ void setEarlyWakeup();
};
status_t destroySurface(const sp<IBinder>& id);
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 2598451..765dcd9 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -113,7 +113,10 @@
constexpr int32_t kAllTransformBits =
ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL |
ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL |
- ANATIVEWINDOW_TRANSFORM_ROTATE_90;
+ ANATIVEWINDOW_TRANSFORM_ROTATE_90 |
+ // We don't expose INVERSE_DISPLAY as an NDK constant, but someone could have read it
+ // from a buffer already set by Camera framework, so we allow it to be forwarded.
+ NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
if (!window || !query(window, NATIVE_WINDOW_IS_VALID))
return -EINVAL;
if ((transform & ~kAllTransformBits) != 0)
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 36da084..fe4ae6c 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -838,6 +838,11 @@
}
Region::const_iterator Region::end() const {
+ // Workaround for b/77643177
+ // mStorage should never be empty, but somehow it is and it's causing
+ // an abort in ubsan
+ if (mStorage.isEmpty()) return mStorage.array();
+
size_t numRects = isRect() ? 1 : mStorage.size() - 1;
return mStorage.array() + numRects;
}
diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
index 10b5d28..baf1f2f 100644
--- a/libs/vr/libdvr/dvr_buffer.cpp
+++ b/libs/vr/libdvr/dvr_buffer.cpp
@@ -43,7 +43,8 @@
ALOGW_IF(
write_buffer->slot != -1,
"dvrWriteBufferDestroy: Destroying a buffer associated with a valid "
- "buffer queue slot. This may indicate possible leaks.");
+ "buffer queue slot. This may indicate possible leaks, buffer_id=%d.",
+ dvrWriteBufferGetId(write_buffer));
delete write_buffer;
}
}
@@ -73,7 +74,8 @@
ALOGW_IF(
read_buffer->slot != -1,
"dvrReadBufferDestroy: Destroying a buffer associated with a valid "
- "buffer queue slot. This may indicate possible leaks.");
+ "buffer queue slot. This may indicate possible leaks, buffer_id=%d.",
+ dvrReadBufferGetId(read_buffer));
delete read_buffer;
}
}
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index 3efe83a..74cee3f 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -389,12 +389,22 @@
return -EINVAL;
}
if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) {
- ALOGE(
- "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released does not "
- "belong to this buffer queue. Releasing buffer: id=%d, buffer in "
- "queue: id=%d",
- read_buffer->read_buffer->id(), consumer_queue_->GetBufferId(slot));
- return -EINVAL;
+ if (consumer_queue_->GetBufferId(slot) > 0) {
+ ALOGE(
+ "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
+ "belong to this queue (queue_id=%d): attempting to release buffer "
+ "(buffer_id=%d) at slot %d which holds a different buffer "
+ "(buffer_id=%d).",
+ consumer_queue_->id(), read_buffer->read_buffer->id(),
+ static_cast<int>(slot), consumer_queue_->GetBufferId(slot));
+ } else {
+ ALOGI(
+ "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
+ "belong to this queue (queue_id=%d): attempting to release buffer "
+ "(buffer_id=%d) at slot %d which is empty.",
+ consumer_queue_->id(), read_buffer->read_buffer->id(),
+ static_cast<int>(slot));
+ }
}
pdx::LocalHandle fence(release_fence_fd);
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 5d9d8b5..2d5f004 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -525,4 +525,55 @@
}
}
+TEST_F(DvrBufferQueueTest, ConsumerReleaseAfterProducerDestroy) {
+ int ret = api_.WriteBufferQueueCreate(
+ kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
+ kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(ret, 0);
+
+ DvrReadBufferQueue* read_queue = nullptr;
+ DvrReadBuffer* rb = nullptr;
+ DvrWriteBuffer* wb = nullptr;
+ DvrNativeBufferMetadata meta1;
+ DvrNativeBufferMetadata meta2;
+ int fence_fd = -1;
+
+ ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+ ASSERT_EQ(ret, 0);
+
+ api_.ReadBufferQueueSetBufferAvailableCallback(
+ read_queue, &BufferAvailableCallback, this);
+
+ // Gain buffer for writing.
+ ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb,
+ &meta1, &fence_fd);
+ ASSERT_EQ(ret, 0);
+ close(fence_fd);
+
+ // Post buffer to the read_queue.
+ ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
+ ASSERT_EQ(ret, 0);
+ wb = nullptr;
+
+ // Acquire buffer for reading.
+ ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb,
+ &meta2, &fence_fd);
+ ASSERT_EQ(ret, 0);
+ close(fence_fd);
+
+ // Destroy the write buffer queue and make sure the reader queue is picking
+ // these events up.
+ api_.WriteBufferQueueDestroy(write_queue_);
+ ret = api_.ReadBufferQueueHandleEvents(read_queue);
+ ASSERT_EQ(0, ret);
+
+ // Release buffer to the write_queue.
+ ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
+ /*release_fence_fd=*/-1);
+ ASSERT_EQ(ret, 0);
+ rb = nullptr;
+
+ api_.ReadBufferQueueDestroy(read_queue);
+}
+
} // namespace
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/displayservice/DisplayEventReceiver.cpp b/services/displayservice/DisplayEventReceiver.cpp
index 5993e44..2bb74c2 100644
--- a/services/displayservice/DisplayEventReceiver.cpp
+++ b/services/displayservice/DisplayEventReceiver.cpp
@@ -102,10 +102,20 @@
switch(buf[i].header.type) {
case FwkReceiver::DISPLAY_EVENT_VSYNC: {
- mCallback->onVsync(timestamp, event.vsync.count);
+ auto ret = mCallback->onVsync(timestamp, event.vsync.count);
+ if (!ret.isOk()) {
+ LOG(ERROR) << "AttachedEvent handleEvent fails on onVsync callback"
+ << " because of " << ret.description();
+ return 0; // remove the callback
+ }
} break;
case FwkReceiver::DISPLAY_EVENT_HOTPLUG: {
- mCallback->onHotplug(timestamp, event.hotplug.connected);
+ auto ret = mCallback->onHotplug(timestamp, event.hotplug.connected);
+ if (!ret.isOk()) {
+ LOG(ERROR) << "AttachedEvent handleEvent fails on onHotplug callback"
+ << " because of " << ret.description();
+ return 0; // remove the callback
+ }
} break;
default: {
LOG(ERROR) << "AttachedEvent handleEvent unknown type: " << type;
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 82300e6..2aa4cd3 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -778,6 +778,7 @@
}
void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
+ ATRACE_CALL();
const State& s(getDrawingState());
computeGeometry(renderArea, getBE().mMesh, useIdentityTransform);
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 6b4f5db..87333d0 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -356,6 +356,7 @@
}
status_t BufferLayerConsumer::bindTextureImageLocked() {
+ ATRACE_CALL();
mRE.checkErrors();
if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == nullptr) {
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 80a90a7..c87b669 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -44,13 +44,13 @@
void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */,
bool useIdentityTransform) const {
- const State& s(getDrawingState());
- if (s.color.a > 0) {
+ half4 color = getColor();
+ if (color.a > 0) {
Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
computeGeometry(renderArea, mesh, useIdentityTransform);
auto& engine(mFlinger->getRenderEngine());
engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */,
- true /* disableTexture */, s.color);
+ true /* disableTexture */, color);
engine.drawMesh(mesh);
engine.disableBlending();
}
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 9e01fd0..7acbd11 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -209,6 +209,28 @@
return BAD_VALUE;
}
+ status_t changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) {
+ if (kTraceDetailedInfo) ATRACE_CALL();
+ Mutex::Autolock lock(mMutex);
+
+ for (size_t i = 0; i < mEventListeners.size(); i++) {
+ if (mEventListeners[i].mCallback == callback) {
+ EventListener& listener = mEventListeners.editItemAt(i);
+ const nsecs_t oldPhase = listener.mPhase;
+ listener.mPhase = phase;
+
+ // Pretend that the last time this event was handled at the same frame but with the
+ // new offset to allow for a seamless offset change without double-firing or
+ // skipping.
+ listener.mLastEventTime -= (oldPhase - phase);
+ mCond.signal();
+ return NO_ERROR;
+ }
+ }
+
+ return BAD_VALUE;
+ }
+
// This method is only here to handle the !SurfaceFlinger::hasSyncFramework
// case.
bool hasAnyEventListeners() {
@@ -487,6 +509,11 @@
return mThread->removeEventListener(callback);
}
+status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) {
+ Mutex::Autolock lock(mMutex);
+ return mThread->changePhaseOffset(callback, phase);
+}
+
void DispSync::setPeriod(nsecs_t period) {
Mutex::Autolock lock(mMutex);
mPeriod = period;
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 9336f4d..077256a 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -113,6 +113,11 @@
// DispSync object.
status_t removeEventListener(Callback* callback);
+ // changePhaseOffset changes the phase offset of an already-registered event callback. The
+ // method will make sure that there is no skipping or double-firing on the listener per frame,
+ // even when changing the offsets multiple times.
+ status_t changePhaseOffset(Callback* callback, nsecs_t phase);
+
// computeNextRefresh computes when the next refresh is expected to begin.
// The periodOffset value can be used to move forward or backward; an
// offset of zero is the next refresh, -1 is the previous refresh, 1 is
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 e844d11..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 {
@@ -281,7 +287,8 @@
rotation) {}
DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqHeight,
uint32_t reqWidth, ISurfaceComposer::Rotation rotation)
- : RenderArea(reqHeight, reqWidth, rotation), mDevice(device), mSourceCrop(sourceCrop) {}
+ : RenderArea(reqHeight, reqWidth, CaptureFill::OPAQUE, rotation), mDevice(device),
+ mSourceCrop(sourceCrop) {}
const Transform& getTransform() const override { return mDevice->getTransform(); }
Rect getBounds() const override { return mDevice->getBounds(); }
@@ -290,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.cpp b/services/surfaceflinger/RenderArea.cpp
index 6225df1..46ec8e6 100644
--- a/services/surfaceflinger/RenderArea.cpp
+++ b/services/surfaceflinger/RenderArea.cpp
@@ -2,6 +2,15 @@
namespace android {
+float RenderArea::getCaptureFillValue(CaptureFill captureFill) {
+ switch(captureFill) {
+ case CaptureFill::CLEAR:
+ return 0.0f;
+ case CaptureFill::OPAQUE:
+ default:
+ return 1.0f;
+ }
+}
/*
* Checks that the requested width and height are valid and updates them to the render area
* dimensions if they are set to 0
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index bf0707f..3630677 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -9,10 +9,15 @@
namespace android {
class RenderArea {
+
public:
- RenderArea(uint32_t reqHeight, uint32_t reqWidth,
+ enum class CaptureFill {CLEAR, OPAQUE};
+
+ static float getCaptureFillValue(CaptureFill captureFill);
+
+ RenderArea(uint32_t reqHeight, uint32_t reqWidth, CaptureFill captureFill,
ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone)
- : mReqHeight(reqHeight), mReqWidth(reqWidth) {
+ : mReqHeight(reqHeight), mReqWidth(reqWidth), mCaptureFill(captureFill) {
mRotationFlags = Transform::fromRotation(rotation);
}
@@ -25,21 +30,23 @@
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; };
+
private:
uint32_t mReqHeight;
uint32_t mReqWidth;
Transform::orientation_flags mRotationFlags;
+ CaptureFill mCaptureFill;
};
} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 1fc3100..1efe0ac 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -293,6 +293,7 @@
}
void GLES20RenderEngine::drawMesh(const Mesh& mesh) {
+ ATRACE_CALL();
if (mesh.getTexCoordsSize()) {
glEnableVertexAttribArray(Program::texCoords);
glVertexAttribPointer(Program::texCoords, mesh.getTexCoordsSize(), GL_FLOAT, GL_FALSE,
@@ -320,10 +321,16 @@
default:
// treat all other dataspaces as sRGB
wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
- if ((mDataSpace & Dataspace::TRANSFER_MASK) & Dataspace::TRANSFER_LINEAR) {
- wideColorState.setInputTransferFunction(Description::TransferFunction::LINEAR);
- } else {
- wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB);
+ switch (static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK)) {
+ case Dataspace::TRANSFER_LINEAR:
+ wideColorState.setInputTransferFunction(
+ Description::TransferFunction::LINEAR);
+ break;
+ default:
+ // treat all other transfer functions as sRGB
+ wideColorState.setInputTransferFunction(
+ Description::TransferFunction::SRGB);
+ break;
}
wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
ALOGV("drawMesh: gamut transform applied");
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5be7951..57f729b 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 {
@@ -296,6 +321,12 @@
auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
+ property_get("debug.sf.early_phase_offset_ns", value, "0");
+ const int earlyWakeupOffsetOffsetNs = atoi(value);
+ ALOGI_IF(earlyWakeupOffsetOffsetNs != 0, "Enabling separate early offset");
+ mVsyncModulator.setPhaseOffsets(sfVsyncPhaseOffsetNs - earlyWakeupOffsetOffsetNs,
+ sfVsyncPhaseOffsetNs);
+
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -522,19 +553,10 @@
return;
}
- // Remove the listener with the old offset
- status_t err = mDispSync->removeEventListener(
- static_cast<DispSync::Callback*>(this));
+ status_t err = mDispSync->changePhaseOffset(static_cast<DispSync::Callback*>(this),
+ mPhaseOffset);
if (err != NO_ERROR) {
- ALOGE("error unregistering vsync callback: %s (%d)",
- strerror(-err), err);
- }
-
- // Add a listener with the new offset
- err = mDispSync->addEventListener(mName, mPhaseOffset,
- static_cast<DispSync::Callback*>(this));
- if (err != NO_ERROR) {
- ALOGE("error registering vsync callback: %s (%d)",
+ ALOGE("error changing vsync offset: %s (%d)",
strerror(-err), err);
}
}
@@ -623,6 +645,7 @@
mSFEventThread = std::make_unique<impl::EventThread>(mSfEventThreadSource.get(), *this, true,
"sfEventThread");
mEventQueue->setEventThread(mSFEventThread.get());
+ mVsyncModulator.setEventThread(mSFEventThread.get());
// Get a RenderEngine for the given display / config (can't fail)
getBE().mRenderEngine =
@@ -692,6 +715,9 @@
ALOGE("Run StartPropertySetThread failed!");
}
+ mLegacySrgbSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(HWC_DISPLAY_PRIMARY,
+ Dataspace::SRGB_LINEAR);
+
ALOGV("Done initializing");
}
@@ -699,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() {
@@ -991,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;
}
@@ -1004,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());
}
@@ -1039,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;
}
@@ -1074,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();
@@ -1340,7 +1387,7 @@
if (sequenceId != getBE().mComposerSequenceId) {
return;
}
- repaintEverythingLocked();
+ repaintEverything();
}
void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
@@ -1498,6 +1545,7 @@
mHadClientComposition = mHadClientComposition ||
getBE().mHwc->hasClientComposition(displayDevice->getHwcDisplayId());
}
+ mVsyncModulator.setLastFrameUsedRenderEngine(mHadClientComposition);
mLayersWithQueuedFrames.clear();
}
@@ -1822,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() {
@@ -1896,7 +1949,7 @@
ALOGV("setUpHWComposer");
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
+ bool dirty = !mDisplays[dpy]->getDirtyRegion(mRepaintEverything).isEmpty();
bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
@@ -1971,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);
}
@@ -1985,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);
}
}
@@ -2122,6 +2166,7 @@
// with mStateLock held to guarantee that mCurrentState won't change
// until the transaction is committed.
+ mVsyncModulator.onTransactionHandled();
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
@@ -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:
@@ -3070,7 +3143,13 @@
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
+ return setTransactionFlags(flags, VSyncModulator::TransactionStart::NORMAL);
+}
+
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
+ VSyncModulator::TransactionStart transactionStart) {
uint32_t old = android_atomic_or(flags, &mTransactionFlags);
+ mVsyncModulator.setTransactionStart(transactionStart);
if ((old & flags)==0) { // wake the server up
signalTransaction();
}
@@ -3159,7 +3238,10 @@
}
// this triggers the transaction
- setTransactionFlags(transactionFlags);
+ const auto start = (flags & eEarlyWakeup)
+ ? VSyncModulator::TransactionStart::EARLY
+ : VSyncModulator::TransactionStart::NORMAL;
+ setTransactionFlags(transactionFlags, start);
// if this is a synchronous transaction, wait for it to take effect
// before returning.
@@ -3634,7 +3716,7 @@
mVisibleRegionsDirty = true;
mHasPoweredOff = true;
- repaintEverythingLocked();
+ repaintEverything();
struct sched_param param = {0};
param.sched_priority = 1;
@@ -3995,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
@@ -4099,9 +4181,9 @@
colorizer.bold(result);
result.append("DispSync configuration: ");
colorizer.reset(result);
- result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, "
- "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
- vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
+ result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, early sf phase %" PRId64
+ " ns, present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+ vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, mVsyncModulator.getEarlyPhaseOffset(),
dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
result.append("\n");
@@ -4491,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;
@@ -4526,25 +4615,31 @@
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;
}
-void SurfaceFlinger::repaintEverythingLocked() {
- android_atomic_or(1, &mRepaintEverything);
- for (size_t dpy = 0; dpy < mDisplays.size(); dpy++) {
- const sp<DisplayDevice>& displayDevice(mDisplays[dpy]);
- const Rect bounds(displayDevice->getBounds());
- displayDevice->dirtyRegion.orSelf(Region(bounds));
- }
- signalTransaction();
-}
-
void SurfaceFlinger::repaintEverything() {
- ConditionalLock _l(mStateLock,
- std::this_thread::get_id() != mMainThreadId);
- repaintEverythingLocked();
+ android_atomic_or(1, &mRepaintEverything);
+ signalTransaction();
}
// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
@@ -4588,11 +4683,12 @@
public:
LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
int32_t reqWidth, int32_t reqHeight, bool childrenOnly)
- : RenderArea(reqHeight, reqWidth),
+ : RenderArea(reqHeight, reqWidth, CaptureFill::CLEAR),
mLayer(layer),
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);
@@ -4601,7 +4697,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:
@@ -4630,16 +4734,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;
@@ -4811,9 +4905,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);
@@ -4825,8 +4918,9 @@
renderArea.getRotationFlags());
engine.disableTexturing();
+ const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());
// redraw the screen entirely...
- engine.clearWithColor(0, 0, 0, 1);
+ engine.clearWithColor(0, 0, 0, alpha);
traverseLayers([&](Layer* layer) {
if (filtering) layer->setFiltering(true);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 89c9cfd..33706da 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -33,6 +33,7 @@
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
#include <utils/threads.h>
+#include <utils/Trace.h>
#include <ui/FenceTime.h>
#include <ui/PixelFormat.h>
@@ -54,6 +55,7 @@
#include "Barrier.h"
#include "DisplayDevice.h"
#include "DispSync.h"
+#include "EventThread.h"
#include "FrameTracker.h"
#include "LayerStats.h"
#include "LayerVector.h"
@@ -61,6 +63,7 @@
#include "SurfaceInterceptor.h"
#include "SurfaceTracing.h"
#include "StartPropertySetThread.h"
+#include "VSyncModulator.h"
#include "DisplayHardware/HWC2.h"
#include "DisplayHardware/HWComposer.h"
@@ -120,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 {
@@ -303,8 +312,6 @@
// force full composition on all displays
void repaintEverything();
- // Can only be called from the main thread or with mStateLock held
- void repaintEverythingLocked();
// returns the default Display
sp<const DisplayDevice> getDefaultDisplayDevice() const {
@@ -464,7 +471,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();
@@ -492,6 +501,7 @@
uint32_t peekTransactionFlags();
// Can only be called from the main thread or with mStateLock held
uint32_t setTransactionFlags(uint32_t flags);
+ uint32_t setTransactionFlags(uint32_t flags, VSyncModulator::TransactionStart transactionStart);
void commitTransaction();
bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
uint32_t setClientStateLocked(const ComposerState& composerState);
@@ -637,9 +647,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;
@@ -765,6 +776,8 @@
std::unique_ptr<EventControlThread> mEventControlThread;
sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
+ VSyncModulator mVsyncModulator;
+
// Can only accessed from the main thread, these members
// don't need synchronization
State mDrawingState{LayerVector::StateSet::Drawing};
@@ -840,7 +853,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);
@@ -850,8 +862,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/surfaceflinger/VSyncModulator.h b/services/surfaceflinger/VSyncModulator.h
new file mode 100644
index 0000000..3e5800e
--- /dev/null
+++ b/services/surfaceflinger/VSyncModulator.h
@@ -0,0 +1,110 @@
+/*
+ * 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 <utils/Errors.h>
+
+#include <mutex>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+
+/*
+ * Modulates the vsync-offsets depending on current SurfaceFlinger state.
+ */
+class VSyncModulator {
+public:
+
+ enum TransactionStart {
+ EARLY,
+ NORMAL
+ };
+
+ // Sets the phase offsets
+ //
+ // early: the phase offset when waking up early. May be the same as late, in which case we don't
+ // shift offsets.
+ // late: the regular sf phase offset.
+ void setPhaseOffsets(nsecs_t early, nsecs_t late) {
+ mEarlyPhaseOffset = early;
+ mLatePhaseOffset = late;
+ mPhaseOffset = late;
+ }
+
+ nsecs_t getEarlyPhaseOffset() const {
+ return mEarlyPhaseOffset;
+ }
+
+ void setEventThread(EventThread* eventThread) {
+ mEventThread = eventThread;
+ }
+
+ void setTransactionStart(TransactionStart transactionStart) {
+ // An early transaction stays an early transaction.
+ if (transactionStart == mTransactionStart || mTransactionStart == TransactionStart::EARLY) {
+ return;
+ }
+ mTransactionStart = transactionStart;
+ updatePhaseOffsets();
+ }
+
+ void onTransactionHandled() {
+ if (mTransactionStart == TransactionStart::NORMAL) return;
+ mTransactionStart = TransactionStart::NORMAL;
+ updatePhaseOffsets();
+ }
+
+ void setLastFrameUsedRenderEngine(bool re) {
+ if (re == mLastFrameUsedRenderEngine) return;
+ mLastFrameUsedRenderEngine = re;
+ updatePhaseOffsets();
+ }
+
+private:
+
+ void updatePhaseOffsets() {
+
+ // Do not change phase offsets if disabled.
+ if (mEarlyPhaseOffset == mLatePhaseOffset) return;
+
+ if (mTransactionStart == TransactionStart::EARLY || mLastFrameUsedRenderEngine) {
+ if (mPhaseOffset != mEarlyPhaseOffset) {
+ if (mEventThread) {
+ mEventThread->setPhaseOffset(mEarlyPhaseOffset);
+ }
+ mPhaseOffset = mEarlyPhaseOffset;
+ }
+ } else {
+ if (mPhaseOffset != mLatePhaseOffset) {
+ if (mEventThread) {
+ mEventThread->setPhaseOffset(mLatePhaseOffset);
+ }
+ mPhaseOffset = mLatePhaseOffset;
+ }
+ }
+ }
+
+ nsecs_t mLatePhaseOffset = 0;
+ nsecs_t mEarlyPhaseOffset = 0;
+ EventThread* mEventThread = nullptr;
+ std::atomic<nsecs_t> mPhaseOffset = 0;
+ std::atomic<TransactionStart> mTransactionStart = TransactionStart::NORMAL;
+ std::atomic<bool> mLastFrameUsedRenderEngine = false;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 4e9db72..a0f12f1 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -1008,6 +1008,32 @@
tolerance);
}
+TEST_F(LayerTransactionTest, SetColorWithParentAlpha_Bug74220420) {
+ sp<SurfaceControl> bufferLayer;
+ sp<SurfaceControl> parentLayer;
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parentWithAlpha", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer(
+ "childWithColor", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
+
+ const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
+ const float alpha = 0.25f;
+ const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
+ // this is handwavy, but the precision loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+ Transaction()
+ .reparent(colorLayer, parentLayer->getHandle())
+ .setColor(colorLayer, color)
+ .setAlpha(parentLayer, alpha)
+ .setLayer(parentLayer, mLayerZBase + 1)
+ .apply();
+ screenshot()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
+ tolerance);
+}
+
TEST_F(LayerTransactionTest, SetColorWithBuffer) {
sp<SurfaceControl> bufferLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
@@ -2332,6 +2358,24 @@
mCapture->expectChildColor(0, 0);
}
+TEST_F(ScreenCaptureTest, CaptureTransparent) {
+ sp<SurfaceControl> child =
+ mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+ 0, mFGSurfaceControl.get());
+
+ fillSurfaceRGBA8(child, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction().show(child).apply(true);
+
+ auto childHandle = child->getHandle();
+
+ // Captures child
+ ScreenCapture::captureLayers(&mCapture, childHandle, {0, 0, 10, 20});
+ mCapture->expectColor(Rect(0, 0, 9, 9), {200, 200, 200, 255});
+ // Area outside of child's bounds is transparent.
+ mCapture->expectColor(Rect(0, 10, 9, 19), {0, 0, 0, 0});
+}
+
// In the following tests we verify successful skipping of a parent layer,
// so we use the same verification logic and only change how we mutate
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,
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 84644a9..1f4df1e 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -983,6 +983,7 @@
{{else if eq $.Name "vkDestroyImage"}}true
{{else if eq $.Name "vkGetPhysicalDeviceProperties"}}true
+ {{else if eq $.Name "vkGetPhysicalDeviceProperties2"}}true
{{else if eq $.Name "vkGetPhysicalDeviceProperties2KHR"}}true
{{end}}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 741fbb8..56bc35e 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -848,7 +848,8 @@
const InstanceData& data = GetData(physicalDevice);
// GPDP2 must be present and enabled on the instance.
- if (!data.driver.GetPhysicalDeviceProperties2KHR)
+ if (!data.driver.GetPhysicalDeviceProperties2KHR &&
+ !data.driver.GetPhysicalDeviceProperties2)
return false;
// Request the android-specific presentation properties via GPDP2
@@ -866,8 +867,12 @@
presentation_properties->pNext = nullptr;
presentation_properties->sharedImage = VK_FALSE;
- data.driver.GetPhysicalDeviceProperties2KHR(physicalDevice,
- &properties);
+ if (data.driver.GetPhysicalDeviceProperties2KHR) {
+ data.driver.GetPhysicalDeviceProperties2KHR(physicalDevice,
+ &properties);
+ } else {
+ data.driver.GetPhysicalDeviceProperties2(physicalDevice, &properties);
+ }
return true;
}
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 51e3abf..ec98b9f 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -494,6 +494,7 @@
INIT_PROC(true, instance, CreateDevice);
INIT_PROC(true, instance, EnumerateDeviceExtensionProperties);
INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups);
+ INIT_PROC(false, instance, GetPhysicalDeviceProperties2);
INIT_PROC_EXT(EXT_debug_report, true, instance, CreateDebugReportCallbackEXT);
INIT_PROC_EXT(EXT_debug_report, true, instance, DestroyDebugReportCallbackEXT);
INIT_PROC_EXT(EXT_debug_report, true, instance, DebugReportMessageEXT);
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 99dc889..14c3aba 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -69,6 +69,7 @@
PFN_vkCreateDevice CreateDevice;
PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups;
+ PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2;
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 6f3790b..6fb3351 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -580,7 +580,7 @@
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
- capabilities->minImageCount = 2;
+ capabilities->minImageCount = max_buffer_count == 1 ? 1 : 2;
capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count);
capabilities->currentExtent =