Merge changes from topics "GL_screen_decor", "VK_screen_decor"
* changes:
Expose VK_FORMAT_R8_UNORM swapchain format if supported by underlying system
Interpret the new R8 EGLConfig properly
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 34ccb21..8da1352 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -11,6 +11,286 @@
# Grant unix world read/write permissions to kernel tracepoints.
# Access control to these files is now entirely in selinux policy.
+ chmod 0755 /sys/kernel/debug/tracing/events
+ chmod 0755 /sys/kernel/debug/tracing/events/binder
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_lock
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_locked
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_set_priority
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_transaction
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_transaction_alloc_buf
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_transaction_received
+ chmod 0755 /sys/kernel/debug/tracing/events/binder/binder_unlock
+ chmod 0755 /sys/kernel/debug/tracing/events/block
+ chmod 0755 /sys/kernel/debug/tracing/events/block/block_rq_complete
+ chmod 0755 /sys/kernel/debug/tracing/events/block/block_rq_issue
+ chmod 0755 /sys/kernel/debug/tracing/events/cgroup
+ chmod 0755 /sys/kernel/debug/tracing/events/clk
+ chmod 0755 /sys/kernel/debug/tracing/events/clk/clk_disable
+ chmod 0755 /sys/kernel/debug/tracing/events/clk/clk_enable
+ chmod 0755 /sys/kernel/debug/tracing/events/clk/clk_set_rate
+ chmod 0755 /sys/kernel/debug/tracing/events/cpufreq_interactive
+ chmod 0755 /sys/kernel/debug/tracing/events/cpuhp
+ chmod 0755 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_enter
+ chmod 0755 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_pause
+ chmod 0755 /sys/kernel/debug/tracing/events/dma_fence
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_es_lookup_extent_enter
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_es_lookup_extent_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_load_inode
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter
+ chmod 0755 /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_get_data_block
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_iget
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin
+ chmod 0755 /sys/kernel/debug/tracing/events/f2fs/f2fs_write_end
+ chmod 0755 /sys/kernel/debug/tracing/events/fence
+ chmod 0755 /sys/kernel/debug/tracing/events/filemap
+ chmod 0755 /sys/kernel/debug/tracing/events/filemap/mm_filemap_add_to_page_cache
+ chmod 0755 /sys/kernel/debug/tracing/events/filemap/mm_filemap_delete_from_page_cache
+ chmod 0755 /sys/kernel/debug/tracing/events/gpu_mem
+ chmod 0755 /sys/kernel/debug/tracing/events/gpu_mem/gpu_mem_total
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_read
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_reply
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_result
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/i2c_write
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_read
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_reply
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_result
+ chmod 0755 /sys/kernel/debug/tracing/events/i2c/smbus_write
+ chmod 0755 /sys/kernel/debug/tracing/events/ion
+ chmod 0755 /sys/kernel/debug/tracing/events/ion/ion_stat
+ chmod 0755 /sys/kernel/debug/tracing/events/ipi
+ chmod 0755 /sys/kernel/debug/tracing/events/ipi/ipi_entry
+ chmod 0755 /sys/kernel/debug/tracing/events/ipi/ipi_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/ipi/ipi_raise
+ chmod 0755 /sys/kernel/debug/tracing/events/irq
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/irq_handler_entry
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/irq_handler_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/softirq_entry
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/softirq_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/softirq_raise
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_entry
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_hi_entry
+ chmod 0755 /sys/kernel/debug/tracing/events/irq/tasklet_hi_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/kmem
+ chmod 0755 /sys/kernel/debug/tracing/events/kmem/ion_heap_grow
+ chmod 0755 /sys/kernel/debug/tracing/events/kmem/ion_heap_shrink
+ chmod 0755 /sys/kernel/debug/tracing/events/kmem/rss_stat
+ chmod 0755 /sys/kernel/debug/tracing/events/lowmemorykiller
+ chmod 0755 /sys/kernel/debug/tracing/events/lowmemorykiller/lowmemory_kill
+ chmod 0755 /sys/kernel/debug/tracing/events/mm_event
+ chmod 0755 /sys/kernel/debug/tracing/events/mm_event/mm_event_record
+ chmod 0755 /sys/kernel/debug/tracing/events/oom
+ chmod 0755 /sys/kernel/debug/tracing/events/oom/mark_victim
+ chmod 0755 /sys/kernel/debug/tracing/events/oom/oom_score_adj_update
+ chmod 0755 /sys/kernel/debug/tracing/events/power
+ chmod 0755 /sys/kernel/debug/tracing/events/power/clock_disable
+ chmod 0755 /sys/kernel/debug/tracing/events/power/clock_enable
+ chmod 0755 /sys/kernel/debug/tracing/events/power/clock_set_rate
+ chmod 0755 /sys/kernel/debug/tracing/events/power/cpu_frequency
+ chmod 0755 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits
+ chmod 0755 /sys/kernel/debug/tracing/events/power/cpu_idle
+ chmod 0755 /sys/kernel/debug/tracing/events/power/gpu_frequency
+ chmod 0755 /sys/kernel/debug/tracing/events/power/suspend_resume
+ chmod 0755 /sys/kernel/debug/tracing/events/sched
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_blocked_reason
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_pi_setprio
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_process_exit
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_process_free
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_switch
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_wakeup
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_wakeup_new
+ chmod 0755 /sys/kernel/debug/tracing/events/sched/sched_waking
+ chmod 0755 /sys/kernel/debug/tracing/events/signal
+ chmod 0755 /sys/kernel/debug/tracing/events/signal/signal_deliver
+ chmod 0755 /sys/kernel/debug/tracing/events/signal/signal_generate
+ chmod 0755 /sys/kernel/debug/tracing/events/sync
+ chmod 0755 /sys/kernel/debug/tracing/events/task
+ chmod 0755 /sys/kernel/debug/tracing/events/task/task_newtask
+ chmod 0755 /sys/kernel/debug/tracing/events/task/task_rename
+ chmod 0755 /sys/kernel/debug/tracing/events/thermal
+ chmod 0755 /sys/kernel/debug/tracing/events/thermal/cdev_update
+ chmod 0755 /sys/kernel/debug/tracing/events/thermal/thermal_temperature
+ chmod 0755 /sys/kernel/debug/tracing/events/vmscan
+ chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin
+ chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end
+ chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep
+ chmod 0755 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake
+ chmod 0755 /sys/kernel/debug/tracing/options
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu0
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu1
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu2
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu3
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu4
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu5
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu6
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu7
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu8
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu9
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu10
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu11
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu12
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu13
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu14
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu15
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu16
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu17
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu18
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu19
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu20
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu21
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu22
+ chmod 0755 /sys/kernel/debug/tracing/per_cpu/cpu23
+ chmod 0755 /sys/kernel/tracing/events
+ chmod 0755 /sys/kernel/tracing/events/binder
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_lock
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_locked
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_set_priority
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_transaction
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_transaction_alloc_buf
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_transaction_received
+ chmod 0755 /sys/kernel/tracing/events/binder/binder_unlock
+ chmod 0755 /sys/kernel/tracing/events/block
+ chmod 0755 /sys/kernel/tracing/events/block/block_rq_complete
+ chmod 0755 /sys/kernel/tracing/events/block/block_rq_issue
+ chmod 0755 /sys/kernel/tracing/events/cgroup
+ chmod 0755 /sys/kernel/tracing/events/clk
+ chmod 0755 /sys/kernel/tracing/events/clk/clk_disable
+ chmod 0755 /sys/kernel/tracing/events/clk/clk_enable
+ chmod 0755 /sys/kernel/tracing/events/clk/clk_set_rate
+ chmod 0755 /sys/kernel/tracing/events/cpufreq_interactive
+ chmod 0755 /sys/kernel/tracing/events/cpuhp
+ chmod 0755 /sys/kernel/tracing/events/cpuhp/cpuhp_enter
+ chmod 0755 /sys/kernel/tracing/events/cpuhp/cpuhp_exit
+ chmod 0755 /sys/kernel/tracing/events/cpuhp/cpuhp_pause
+ chmod 0755 /sys/kernel/tracing/events/dma_fence
+ chmod 0755 /sys/kernel/tracing/events/ext4
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_da_write_begin
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_da_write_end
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_es_lookup_extent_enter
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_es_lookup_extent_exit
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_load_inode
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_sync_file_enter
+ chmod 0755 /sys/kernel/tracing/events/ext4/ext4_sync_file_exit
+ chmod 0755 /sys/kernel/tracing/events/f2fs
+ chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block
+ chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_iget
+ chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_enter
+ chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_sync_file_exit
+ chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_write_begin
+ chmod 0755 /sys/kernel/tracing/events/f2fs/f2fs_write_end
+ chmod 0755 /sys/kernel/tracing/events/fence
+ chmod 0755 /sys/kernel/tracing/events/filemap
+ chmod 0755 /sys/kernel/tracing/events/filemap/mm_filemap_add_to_page_cache
+ chmod 0755 /sys/kernel/tracing/events/filemap/mm_filemap_delete_from_page_cache
+ chmod 0755 /sys/kernel/tracing/events/gpu_mem
+ chmod 0755 /sys/kernel/tracing/events/gpu_mem/gpu_mem_total
+ chmod 0755 /sys/kernel/tracing/events/i2c
+ chmod 0755 /sys/kernel/tracing/events/i2c/i2c_read
+ chmod 0755 /sys/kernel/tracing/events/i2c/i2c_reply
+ chmod 0755 /sys/kernel/tracing/events/i2c/i2c_result
+ chmod 0755 /sys/kernel/tracing/events/i2c/i2c_write
+ chmod 0755 /sys/kernel/tracing/events/i2c/smbus_read
+ chmod 0755 /sys/kernel/tracing/events/i2c/smbus_reply
+ chmod 0755 /sys/kernel/tracing/events/i2c/smbus_result
+ chmod 0755 /sys/kernel/tracing/events/i2c/smbus_write
+ chmod 0755 /sys/kernel/tracing/events/ion
+ chmod 0755 /sys/kernel/tracing/events/ion/ion_stat
+ chmod 0755 /sys/kernel/tracing/events/ipi
+ chmod 0755 /sys/kernel/tracing/events/ipi/ipi_entry
+ chmod 0755 /sys/kernel/tracing/events/ipi/ipi_exit
+ chmod 0755 /sys/kernel/tracing/events/ipi/ipi_raise
+ chmod 0755 /sys/kernel/tracing/events/irq
+ chmod 0755 /sys/kernel/tracing/events/irq/irq_handler_entry
+ chmod 0755 /sys/kernel/tracing/events/irq/irq_handler_exit
+ chmod 0755 /sys/kernel/tracing/events/irq/softirq_entry
+ chmod 0755 /sys/kernel/tracing/events/irq/softirq_exit
+ chmod 0755 /sys/kernel/tracing/events/irq/softirq_raise
+ chmod 0755 /sys/kernel/tracing/events/irq/tasklet_entry
+ chmod 0755 /sys/kernel/tracing/events/irq/tasklet_exit
+ chmod 0755 /sys/kernel/tracing/events/irq/tasklet_hi_entry
+ chmod 0755 /sys/kernel/tracing/events/irq/tasklet_hi_exit
+ chmod 0755 /sys/kernel/tracing/events/kmem
+ chmod 0755 /sys/kernel/tracing/events/kmem/ion_heap_grow
+ chmod 0755 /sys/kernel/tracing/events/kmem/ion_heap_shrink
+ chmod 0755 /sys/kernel/tracing/events/kmem/rss_stat
+ chmod 0755 /sys/kernel/tracing/events/lowmemorykiller
+ chmod 0755 /sys/kernel/tracing/events/lowmemorykiller/lowmemory_kill
+ chmod 0755 /sys/kernel/tracing/events/mm_event
+ chmod 0755 /sys/kernel/tracing/events/mm_event/mm_event_record
+ chmod 0755 /sys/kernel/tracing/events/oom
+ chmod 0755 /sys/kernel/tracing/events/oom/mark_victim
+ chmod 0755 /sys/kernel/tracing/events/oom/oom_score_adj_update
+ chmod 0755 /sys/kernel/tracing/events/power
+ chmod 0755 /sys/kernel/tracing/events/power/clock_disable
+ chmod 0755 /sys/kernel/tracing/events/power/clock_enable
+ chmod 0755 /sys/kernel/tracing/events/power/clock_set_rate
+ chmod 0755 /sys/kernel/tracing/events/power/cpu_frequency
+ chmod 0755 /sys/kernel/tracing/events/power/cpu_frequency_limits
+ chmod 0755 /sys/kernel/tracing/events/power/cpu_idle
+ chmod 0755 /sys/kernel/tracing/events/power/gpu_frequency
+ chmod 0755 /sys/kernel/tracing/events/power/suspend_resume
+ chmod 0755 /sys/kernel/tracing/events/sched
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_blocked_reason
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_cpu_hotplug
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_pi_setprio
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_process_exit
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_process_free
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_switch
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_wakeup
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_wakeup_new
+ chmod 0755 /sys/kernel/tracing/events/sched/sched_waking
+ chmod 0755 /sys/kernel/tracing/events/signal
+ chmod 0755 /sys/kernel/tracing/events/signal/signal_deliver
+ chmod 0755 /sys/kernel/tracing/events/signal/signal_generate
+ chmod 0755 /sys/kernel/tracing/events/sync
+ chmod 0755 /sys/kernel/tracing/events/task
+ chmod 0755 /sys/kernel/tracing/events/task/task_newtask
+ chmod 0755 /sys/kernel/tracing/events/task/task_rename
+ chmod 0755 /sys/kernel/tracing/events/thermal
+ chmod 0755 /sys/kernel/tracing/events/thermal/cdev_update
+ chmod 0755 /sys/kernel/tracing/events/thermal/thermal_temperature
+ chmod 0755 /sys/kernel/tracing/events/vmscan
+ chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin
+ chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end
+ chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep
+ chmod 0755 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake
+ chmod 0755 /sys/kernel/tracing/options
+ chmod 0755 /sys/kernel/tracing/per_cpu
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu0
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu1
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu2
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu3
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu4
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu5
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu6
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu7
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu8
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu9
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu10
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu11
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu12
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu13
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu14
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu15
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu16
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu17
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu18
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu19
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu20
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu21
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu22
+ chmod 0755 /sys/kernel/tracing/per_cpu/cpu23
chmod 0666 /sys/kernel/debug/tracing/trace_clock
chmod 0666 /sys/kernel/tracing/trace_clock
chmod 0666 /sys/kernel/debug/tracing/buffer_size_kb
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 4561d6e..e2fc18d 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -24,13 +24,15 @@
target: {
darwin: {
enabled: false,
- }
+ },
},
apex_available: [
"//apex_available:platform",
"com.android.compos",
+ "com.android.uwb",
"com.android.virt",
],
+ min_sdk_version: "current",
}
rust_library {
@@ -45,7 +47,7 @@
target: {
darwin: {
enabled: false,
- }
+ },
},
apex_available: [
"//apex_available:platform",
@@ -69,13 +71,15 @@
target: {
darwin: {
enabled: false,
- }
+ },
},
apex_available: [
"//apex_available:platform",
"com.android.compos",
+ "com.android.uwb",
"com.android.virt",
],
+ min_sdk_version: "current",
lints: "none",
clippy_lints: "none",
}
@@ -88,20 +92,31 @@
bindgen_flags: [
// Unfortunately the only way to specify the rust_non_exhaustive enum
// style for a type is to make it the default
- "--default-enum-style", "rust_non_exhaustive",
+ "--default-enum-style",
+ "rust_non_exhaustive",
// and then specify constified enums for the enums we don't want
// rustified
- "--constified-enum", "android::c_interface::consts::.*",
+ "--constified-enum",
+ "android::c_interface::consts::.*",
- "--allowlist-type", "android::c_interface::.*",
- "--allowlist-type", "AStatus",
- "--allowlist-type", "AIBinder_Class",
- "--allowlist-type", "AIBinder",
- "--allowlist-type", "AIBinder_Weak",
- "--allowlist-type", "AIBinder_DeathRecipient",
- "--allowlist-type", "AParcel",
- "--allowlist-type", "binder_status_t",
- "--allowlist-function", ".*",
+ "--allowlist-type",
+ "android::c_interface::.*",
+ "--allowlist-type",
+ "AStatus",
+ "--allowlist-type",
+ "AIBinder_Class",
+ "--allowlist-type",
+ "AIBinder",
+ "--allowlist-type",
+ "AIBinder_Weak",
+ "--allowlist-type",
+ "AIBinder_DeathRecipient",
+ "--allowlist-type",
+ "AParcel",
+ "--allowlist-type",
+ "binder_status_t",
+ "--allowlist-function",
+ ".*",
],
shared_libs: [
"libbinder_ndk",
@@ -127,8 +142,10 @@
apex_available: [
"//apex_available:platform",
"com.android.compos",
+ "com.android.uwb",
"com.android.virt",
],
+ min_sdk_version: "current",
}
// TODO(b/184872979): remove once the Rust API is created.
@@ -142,8 +159,10 @@
],
apex_available: [
"com.android.compos",
+ "com.android.uwb",
"com.android.virt",
],
+ min_sdk_version: "current",
}
rust_test {
diff --git a/libs/graphicsenv/GpuStatsInfo.cpp b/libs/graphicsenv/GpuStatsInfo.cpp
index f2d0943..858739c 100644
--- a/libs/graphicsenv/GpuStatsInfo.cpp
+++ b/libs/graphicsenv/GpuStatsInfo.cpp
@@ -88,6 +88,7 @@
if ((status = parcel->writeBool(cpuVulkanInUse)) != OK) return status;
if ((status = parcel->writeBool(falsePrerotation)) != OK) return status;
if ((status = parcel->writeBool(gles1InUse)) != OK) return status;
+ if ((status = parcel->writeBool(angleInUse)) != OK) return status;
return OK;
}
@@ -101,6 +102,7 @@
if ((status = parcel->readBool(&cpuVulkanInUse)) != OK) return status;
if ((status = parcel->readBool(&falsePrerotation)) != OK) return status;
if ((status = parcel->readBool(&gles1InUse)) != OK) return status;
+ if ((status = parcel->readBool(&angleInUse)) != OK) return status;
return OK;
}
@@ -111,6 +113,7 @@
StringAppendF(&result, "cpuVulkanInUse = %d\n", cpuVulkanInUse);
StringAppendF(&result, "falsePrerotation = %d\n", falsePrerotation);
StringAppendF(&result, "gles1InUse = %d\n", gles1InUse);
+ StringAppendF(&result, "angleInUse = %d\n", angleInUse);
result.append("glDriverLoadingTime:");
for (int32_t loadingTime : glDriverLoadingTime) {
StringAppendF(&result, " %d", loadingTime);
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
index 9aba69f..5b513d2 100644
--- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
@@ -16,6 +16,7 @@
#pragma once
+#include <chrono>
#include <string>
#include <vector>
@@ -52,7 +53,7 @@
};
/*
- * class for transporting gpu app stats from GpuService to authorized recipents.
+ * class for transporting gpu app stats from GpuService to authorized recipients.
* This class is intended to be a data container.
*/
class GpuStatsAppInfo : public Parcelable {
@@ -72,6 +73,9 @@
bool cpuVulkanInUse = false;
bool falsePrerotation = false;
bool gles1InUse = false;
+ bool angleInUse = false;
+
+ std::chrono::time_point<std::chrono::system_clock> lastAccessTime;
};
/*
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index dd50ca7..85a4b67 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -132,12 +132,11 @@
}
}
-BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
- int width, int height, int32_t format)
- : mSurfaceControl(surface),
- mSize(width, height),
+BLASTBufferQueue::BLASTBufferQueue(const std::string& name)
+ : mSurfaceControl(nullptr),
+ mSize(1, 1),
mRequestedSize(mSize),
- mFormat(format),
+ mFormat(PIXEL_FORMAT_RGBA_8888),
mSyncTransaction(nullptr) {
createBufferQueue(&mProducer, &mConsumer);
// since the adapter is in the client process, set dequeue timeout
@@ -158,25 +157,21 @@
mBufferItemConsumer->setName(String8(consumerName.c_str()));
mBufferItemConsumer->setFrameAvailableListener(this);
mBufferItemConsumer->setBufferFreedListener(this);
- mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
- mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
mBufferItemConsumer->setBlastBufferQueue(this);
ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
-
- mTransformHint = mSurfaceControl->getTransformHint();
- mBufferItemConsumer->setTransformHint(mTransformHint);
- SurfaceComposerClient::Transaction()
- .setFlags(surface, layer_state_t::eEnableBackpressure,
- layer_state_t::eEnableBackpressure)
- .setApplyToken(mApplyToken)
- .apply();
mNumAcquired = 0;
mNumFrameAvailable = 0;
- BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", width,
- height, format, mTransformHint);
+ BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", mSize.width,
+ mSize.height, mFormat, mTransformHint);
+}
+
+BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
+ int width, int height, int32_t format)
+ : BLASTBufferQueue(name) {
+ update(surface, width, height, format);
}
BLASTBufferQueue::~BLASTBufferQueue() {
@@ -228,12 +223,9 @@
// If the buffer supports scaling, update the frame immediately since the client may
// want to scale the existing buffer to the new size.
mSize = mRequestedSize;
- // We only need to update the scale if we've received at least one buffer. The reason
- // for this is the scale is calculated based on the requested size and buffer size.
- // If there's no buffer, the scale will always be 1.
SurfaceComposerClient::Transaction* destFrameTransaction =
(outTransaction) ? outTransaction : &t;
- if (mSurfaceControl != nullptr && mLastBufferInfo.hasBuffer) {
+ if (mSurfaceControl != nullptr) {
destFrameTransaction->setDestinationFrame(mSurfaceControl,
Rect(0, 0, newSize.getWidth(),
newSize.getHeight()));
@@ -508,9 +500,8 @@
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
- const bool sizeHasChanged = mRequestedSize != mSize;
+ const bool updateDestinationFrame = mRequestedSize != mSize;
mSize = mRequestedSize;
- const bool updateDestinationFrame = sizeHasChanged || !mLastBufferInfo.hasBuffer;
Rect crop = computeCrop(bufferItem);
mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index cd1c810..ec0573a 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -550,9 +550,7 @@
}
bool InputWindowCommands::empty() const {
- bool empty = true;
- empty = focusRequests.empty() && !syncInputWindows;
- return empty;
+ return focusRequests.empty() && !syncInputWindows;
}
void InputWindowCommands::clear() {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index e1fe26a..aafa5e4 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -62,6 +62,14 @@
ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService);
+namespace {
+// Initialize transaction id counter used to generate transaction ids
+std::atomic<uint32_t> idCounter = 0;
+int64_t generateId() {
+ return (((int64_t)getpid()) << 32) | ++idCounter;
+}
+} // namespace
+
ComposerService::ComposerService()
: Singleton<ComposerService>() {
Mutex::Autolock _l(mLock);
@@ -535,10 +543,6 @@
// ---------------------------------------------------------------------------
-// Initialize transaction id counter used to generate transaction ids
-// Transactions will start counting at 1, 0 is used for invalid transactions
-std::atomic<uint32_t> SurfaceComposerClient::Transaction::idCounter = 1;
-
SurfaceComposerClient::Transaction::Transaction() {
mId = generateId();
}
@@ -570,9 +574,6 @@
return nullptr;
}
-int64_t SurfaceComposerClient::Transaction::generateId() {
- return (((int64_t)getpid()) << 32) | idCounter++;
-}
status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) {
const uint32_t forceSynchronous = parcel->readUint32();
@@ -825,7 +826,7 @@
sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
sf->setTransactionState(FrameTimelineInfo{}, {}, {}, 0, applyToken, {}, systemTime(), true,
- uncacheBuffer, false, {}, 0 /* Undefined transactionId */);
+ uncacheBuffer, false, {}, generateId());
}
void SurfaceComposerClient::Transaction::cacheBuffers() {
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index d766173..8a2f392 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -74,6 +74,7 @@
: public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener
{
public:
+ BLASTBufferQueue(const std::string& name);
BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width,
int height, int32_t format);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0fe1253..17b4846 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -366,8 +366,6 @@
class Transaction : public Parcelable {
private:
- static std::atomic<uint32_t> idCounter;
- int64_t generateId();
void releaseBufferIfOverwriting(const layer_state_t& state);
protected:
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index c447d31..18a4b2d 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -176,6 +176,8 @@
static_cast<int>(HAL_DATASPACE_BT2020_HLG));
static_assert(static_cast<int>(ADATASPACE_BT2020_ITU_HLG) ==
static_cast<int>(HAL_DATASPACE_BT2020_ITU_HLG));
+ static_assert(static_cast<int>(DEPTH) == static_cast<int>(HAL_DATASPACE_DEPTH));
+ static_assert(static_cast<int>(DYNAMIC_DEPTH) == static_cast<int>(HAL_DATASPACE_DYNAMIC_DEPTH));
if (!window || !query(window, NATIVE_WINDOW_IS_VALID) ||
!isDataSpaceValid(window, dataSpace)) {
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 30ac220..771844f 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -541,7 +541,21 @@
*
* Use limited range, hybrid log gamma transfer and BT2020 standard.
*/
- ADATASPACE_BT2020_ITU_HLG = 302383104 // STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED
+ ADATASPACE_BT2020_ITU_HLG = 302383104, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED
+
+ /**
+ * Depth:
+ *
+ * This value is valid with formats HAL_PIXEL_FORMAT_Y16 and HAL_PIXEL_FORMAT_BLOB.
+ */
+ DEPTH = 4096,
+
+ /**
+ * ISO 16684-1:2011(E) Dynamic Depth:
+ *
+ * Embedded depth metadata following the dynamic depth specification.
+ */
+ DYNAMIC_DEPTH = 4098
};
__END_DECLS
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index d395d06..b4cab39 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -57,8 +57,10 @@
// orientation.
uint32_t orientation = ui::Transform::ROT_0;
- // SDR white point, -1f if unknown
- float sdrWhitePointNits = -1.f;
+ // Target luminance of the display. -1f if unknown.
+ // All layers will be dimmed by (max(layer white points) / targetLuminanceNits).
+ // If the target luminance is unknown, then no display-level dimming occurs.
+ float targetLuminanceNits = -1.f;
};
static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) {
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 715f3f8..702e8b0 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -171,6 +171,12 @@
// Name associated with the layer for debugging purposes.
std::string name;
+
+ // Luminance of the white point for this layer. Used for linear dimming.
+ // Individual layers will be dimmed by (whitePointNits / maxWhitePoint).
+ // If white point nits are unknown, then this layer is assumed to have the
+ // same luminance as the brightest layer in the scene.
+ float whitePointNits = -1.f;
};
// Keep in sync with custom comparison function in
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 376e279..cc90946 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -46,6 +46,7 @@
#include <cmath>
#include <cstdint>
#include <memory>
+#include <numeric>
#include "../gl/GLExtensions.h"
#include "Cache.h"
@@ -612,33 +613,33 @@
AutoBackendTexture::CleanupManager& mMgr;
};
-sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp<SkShader> shader,
- const LayerSettings& layer,
- const DisplaySettings& display,
- bool undoPremultipliedAlpha,
- bool requiresLinearEffect) {
- const auto stretchEffect = layer.stretchEffect;
+sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(
+ const RuntimeEffectShaderParameters& parameters) {
// The given surface will be stretched by HWUI via matrix transformation
// which gets similar results for most surfaces
// Determine later on if we need to leverage the stertch shader within
// surface flinger
+ const auto& stretchEffect = parameters.layer.stretchEffect;
+ auto shader = parameters.shader;
if (stretchEffect.hasEffect()) {
- const auto targetBuffer = layer.source.buffer.buffer;
+ const auto targetBuffer = parameters.layer.source.buffer.buffer;
const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
- if (graphicBuffer && shader) {
+ if (graphicBuffer && parameters.shader) {
shader = mStretchShaderFactory.createSkShader(shader, stretchEffect);
}
}
- if (requiresLinearEffect) {
- const ui::Dataspace inputDataspace =
- mUseColorManagement ? layer.sourceDataspace : ui::Dataspace::V0_SRGB_LINEAR;
- const ui::Dataspace outputDataspace =
- mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR;
+ if (parameters.requiresLinearEffect) {
+ const ui::Dataspace inputDataspace = mUseColorManagement ? parameters.layer.sourceDataspace
+ : ui::Dataspace::V0_SRGB_LINEAR;
+ const ui::Dataspace outputDataspace = mUseColorManagement
+ ? parameters.display.outputDataspace
+ : ui::Dataspace::V0_SRGB_LINEAR;
- auto effect = shaders::LinearEffect{.inputDataspace = inputDataspace,
- .outputDataspace = outputDataspace,
- .undoPremultipliedAlpha = undoPremultipliedAlpha};
+ auto effect =
+ shaders::LinearEffect{.inputDataspace = inputDataspace,
+ .outputDataspace = outputDataspace,
+ .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha};
auto effectIter = mRuntimeEffects.find(effect);
sk_sp<SkRuntimeEffect> runtimeEffect = nullptr;
@@ -648,16 +649,16 @@
} else {
runtimeEffect = effectIter->second;
}
- float maxLuminance = layer.source.buffer.maxLuminanceNits;
- // If the buffer doesn't have a max luminance, treat it as SDR & use the display's SDR
- // white point
- if (maxLuminance <= 0.f) {
- maxLuminance = display.sdrWhitePointNits;
- }
- return createLinearEffectShader(shader, effect, runtimeEffect, layer.colorTransform,
- display.maxLuminance, maxLuminance);
+ mat4 colorTransform = parameters.layer.colorTransform;
+
+ colorTransform *=
+ mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio,
+ parameters.layerDimmingRatio, 1.f));
+ return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform,
+ parameters.display.maxLuminance,
+ parameters.layer.source.buffer.maxLuminanceNits);
}
- return shader;
+ return parameters.shader;
}
void SkiaGLRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
@@ -730,6 +731,11 @@
return roundedRect;
}
+static bool equalsWithinMargin(float expected, float value, float margin) {
+ LOG_ALWAYS_FATAL_IF(margin < 0.f, "Margin is negative!");
+ return std::abs(expected - value) < margin;
+}
+
void SkiaGLRenderEngine::drawLayersInternal(
const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
const DisplaySettings& display, const std::vector<LayerSettings>& layers,
@@ -791,6 +797,18 @@
const bool ctModifiesAlpha =
displayColorTransform && !displayColorTransform->isAlphaUnchanged();
+ // Find the max layer white point to determine the max luminance of the scene...
+ const float maxLayerWhitePoint = std::transform_reduce(
+ layers.cbegin(), layers.cend(), 0.f,
+ [](float left, float right) { return std::max(left, right); },
+ [&](const auto& l) { return l.whitePointNits; });
+
+ // ...and compute the dimming ratio if dimming is requested
+ const float displayDimmingRatio = display.targetLuminanceNits > 0.f &&
+ maxLayerWhitePoint > 0.f && display.targetLuminanceNits > maxLayerWhitePoint
+ ? maxLayerWhitePoint / display.targetLuminanceNits
+ : 1.f;
+
// Find if any layers have requested blur, we'll use that info to decide when to render to an
// offscreen buffer and when to render to the native buffer.
sk_sp<SkSurface> activeSurface(dstSurface);
@@ -964,11 +982,14 @@
drawShadow(canvas, rrect, layer.shadow);
}
+ const float layerDimmingRatio = layer.whitePointNits <= 0.f
+ ? displayDimmingRatio
+ : (layer.whitePointNits / maxLayerWhitePoint) * displayDimmingRatio;
+
const bool requiresLinearEffect = layer.colorTransform != mat4() ||
(mUseColorManagement &&
needsToneMapping(layer.sourceDataspace, display.outputDataspace)) ||
- (display.sdrWhitePointNits > 0.f &&
- display.sdrWhitePointNits != display.maxLuminance);
+ !equalsWithinMargin(1.f, layerDimmingRatio, 0.001f);
// quick abort from drawing the remaining portion of the layer
if (layer.skipContentDraw ||
@@ -1067,9 +1088,20 @@
toSkColorSpace(layerDataspace)));
}
- paint.setShader(createRuntimeEffectShader(shader, layer, display,
- !item.isOpaque && item.usePremultipliedAlpha,
- requiresLinearEffect));
+ paint.setShader(createRuntimeEffectShader(
+ RuntimeEffectShaderParameters{.shader = shader,
+ .layer = layer,
+ .display = display,
+ .undoPremultipliedAlpha = !item.isOpaque &&
+ item.usePremultipliedAlpha,
+ .requiresLinearEffect = requiresLinearEffect,
+ .layerDimmingRatio = layerDimmingRatio}));
+
+ // Turn on dithering when dimming beyond this threshold.
+ static constexpr float kDimmingThreshold = 0.2f;
+ if (layerDimmingRatio <= kDimmingThreshold) {
+ paint.setDither(true);
+ }
paint.setAlphaf(layer.alpha);
} else {
ATRACE_NAME("DrawColor");
@@ -1079,9 +1111,13 @@
.fB = color.b,
.fA = layer.alpha},
toSkColorSpace(layerDataspace));
- paint.setShader(createRuntimeEffectShader(shader, layer, display,
- /* undoPremultipliedAlpha */ false,
- requiresLinearEffect));
+ paint.setShader(createRuntimeEffectShader(
+ RuntimeEffectShaderParameters{.shader = shader,
+ .layer = layer,
+ .display = display,
+ .undoPremultipliedAlpha = false,
+ .requiresLinearEffect = requiresLinearEffect,
+ .layerDimmingRatio = layerDimmingRatio}));
}
if (layer.disableBlending) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 53792f9..a650313 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -106,12 +106,18 @@
void initCanvas(SkCanvas* canvas, const DisplaySettings& display);
void drawShadow(SkCanvas* canvas, const SkRRect& casterRRect,
const ShadowSettings& shadowSettings);
+
// If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned.
// Otherwise it returns the input shader.
- sk_sp<SkShader> createRuntimeEffectShader(sk_sp<SkShader> shader, const LayerSettings& layer,
- const DisplaySettings& display,
- bool undoPremultipliedAlpha,
- bool requiresLinearEffect);
+ struct RuntimeEffectShaderParameters {
+ sk_sp<SkShader> shader;
+ const LayerSettings& layer;
+ const DisplaySettings& display;
+ bool undoPremultipliedAlpha;
+ bool requiresLinearEffect;
+ float layerDimmingRatio;
+ };
+ sk_sp<SkShader> createRuntimeEffectShader(const RuntimeEffectShaderParameters&);
EGLDisplay mEGLDisplay;
EGLContext mEGLContext;
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 8259063..eb2b2dc 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -208,6 +208,21 @@
renderengine::ExternalTexture::Usage::WRITEABLE);
}
+ std::shared_ptr<renderengine::ExternalTexture> allocateAndFillSourceBuffer(uint32_t width,
+ uint32_t height,
+ ubyte4 color) {
+ const auto buffer = allocateSourceBuffer(width, height);
+ uint8_t* pixels;
+ buffer->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
+ pixels[0] = color.r;
+ pixels[1] = color.g;
+ pixels[2] = color.b;
+ pixels[3] = color.a;
+ buffer->getBuffer()->unlock();
+ return buffer;
+ }
+
RenderEngineTest() {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
@@ -2195,6 +2210,133 @@
expectBufferColor(rect, 0, 128, 0, 128);
}
+TEST_P(RenderEngineTest, testDimming) {
+ if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+ return;
+ }
+ initializeRenderEngine();
+
+ const auto displayRect = Rect(3, 1);
+ const renderengine::DisplaySettings display{
+ .physicalDisplay = displayRect,
+ .clip = displayRect,
+ .outputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .targetLuminanceNits = 1000.f,
+ };
+
+ const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255));
+ const auto blueBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 0, 255, 255));
+ const auto redBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(255, 0, 0, 255));
+
+ const renderengine::LayerSettings greenLayer{
+ .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = greenBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .whitePointNits = 200.f,
+ };
+
+ const renderengine::LayerSettings blueLayer{
+ .geometry.boundaries = FloatRect(1.f, 0.f, 2.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = blueBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .whitePointNits = 1000.f / 51.f,
+ };
+
+ const renderengine::LayerSettings redLayer{
+ .geometry.boundaries = FloatRect(2.f, 0.f, 3.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = redBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ // When the white point is not set for a layer, just ignore it and treat it as the same
+ // as the max layer
+ .whitePointNits = -1.f,
+ };
+
+ std::vector<renderengine::LayerSettings> layers{greenLayer, blueLayer, redLayer};
+ invokeDraw(display, layers);
+
+ expectBufferColor(Rect(1, 1), 0, 51, 0, 255, 1);
+ expectBufferColor(Rect(1, 0, 2, 1), 0, 0, 5, 255, 1);
+ expectBufferColor(Rect(2, 0, 3, 1), 51, 0, 0, 255, 1);
+}
+
+TEST_P(RenderEngineTest, testDimming_withoutTargetLuminance) {
+ initializeRenderEngine();
+ if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+ return;
+ }
+
+ const auto displayRect = Rect(2, 1);
+ const renderengine::DisplaySettings display{
+ .physicalDisplay = displayRect,
+ .clip = displayRect,
+ .outputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .targetLuminanceNits = -1.f,
+ };
+
+ const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255));
+ const auto blueBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 0, 255, 255));
+
+ const renderengine::LayerSettings greenLayer{
+ .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = greenBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .whitePointNits = 200.f,
+ };
+
+ const renderengine::LayerSettings blueLayer{
+ .geometry.boundaries = FloatRect(1.f, 0.f, 2.f, 1.f),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = blueBuffer,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR,
+ .whitePointNits = 1000.f,
+ };
+
+ std::vector<renderengine::LayerSettings> layers{greenLayer, blueLayer};
+ invokeDraw(display, layers);
+
+ expectBufferColor(Rect(1, 1), 0, 51, 0, 255, 1);
+ expectBufferColor(Rect(1, 0, 2, 1), 0, 0, 255, 255);
+}
+
TEST_P(RenderEngineTest, test_isOpaque) {
initializeRenderEngine();
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 36d001f..a7b5900 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -225,6 +225,11 @@
"libui_headers",
],
min_sdk_version: "29",
+
+ pgo: {
+ sampling: true,
+ profile_file: "libui/libui.profdata",
+ },
}
cc_library_headers {
diff --git a/libs/ui/include_types/ui/DataspaceUtils.h b/libs/ui/include_types/ui/DataspaceUtils.h
new file mode 100644
index 0000000..a461cb4
--- /dev/null
+++ b/libs/ui/include_types/ui/DataspaceUtils.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 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 <ui/GraphicTypes.h>
+
+namespace android {
+
+inline bool isHdrDataspace(ui::Dataspace dataspace) {
+ const auto transfer = dataspace & HAL_DATASPACE_TRANSFER_MASK;
+
+ return transfer == HAL_DATASPACE_TRANSFER_ST2084 || transfer == HAL_DATASPACE_TRANSFER_HLG;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 0ee15f2..22fbf45 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -163,3 +163,13 @@
"-Werror",
],
}
+
+cc_test {
+ name: "DataspaceUtils_test",
+ shared_libs: ["libui"],
+ srcs: ["DataspaceUtils_test.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/libs/ui/tests/DataspaceUtils_test.cpp b/libs/ui/tests/DataspaceUtils_test.cpp
new file mode 100644
index 0000000..3e09671
--- /dev/null
+++ b/libs/ui/tests/DataspaceUtils_test.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "DataspaceUtilsTest"
+
+#include <gtest/gtest.h>
+#include <ui/DataspaceUtils.h>
+
+namespace android {
+
+class DataspaceUtilsTest : public testing::Test {};
+
+TEST_F(DataspaceUtilsTest, isHdrDataspace) {
+ EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_ITU_HLG));
+ EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_ITU_PQ));
+ EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_PQ));
+ EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_HLG));
+
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SRGB_LINEAR));
+ // scRGB defines a very wide gamut but not an expanded luminance range
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SCRGB_LINEAR));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SRGB));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SCRGB));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_JFIF));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_BT601_625));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_BT601_525));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_BT709));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DCI_P3_LINEAR));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DCI_P3));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DISPLAY_P3_LINEAR));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DISPLAY_P3));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::ADOBE_RGB));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::BT2020_LINEAR));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::BT2020));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::BT2020_ITU));
+ EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DISPLAY_BT2020));
+}
+
+} // namespace android
diff --git a/opengl/libs/EGL/GLES_layers.md b/opengl/libs/EGL/GLES_layers.md
index bfc44db..f6a8f14 100644
--- a/opengl/libs/EGL/GLES_layers.md
+++ b/opengl/libs/EGL/GLES_layers.md
@@ -251,7 +251,7 @@
- Secondly, if you want to determine from an application that can't call out to ADB for this, you can check for the [EGL_ANDROID_GLES_layers](../../specs/EGL_ANDROID_GLES_layers.txt). It simply indicates support of this layering system:
```cpp
std::string display_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
- if (display_extension.find("EGL_ANDROID_GLES_layers") != std::string::npos)
+ if (display_extensions.find("EGL_ANDROID_GLES_layers") != std::string::npos)
{
// Layers are supported!
}
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
index 220952d..d033453 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -84,6 +84,38 @@
}
}
+void GpuStats::purgeOldDriverStats() {
+ ALOG_ASSERT(mAppStats.size() == MAX_NUM_APP_RECORDS);
+
+ struct GpuStatsApp {
+ // Key is <app package name>+<driver version code>.
+ const std::string *appStatsKey = nullptr;
+ const std::chrono::time_point<std::chrono::system_clock> *lastAccessTime = nullptr;
+ };
+ std::vector<GpuStatsApp> gpuStatsApps(MAX_NUM_APP_RECORDS);
+
+ // Create a list of pointers to package names and their last access times.
+ int index = 0;
+ for (const auto & [appStatsKey, gpuStatsAppInfo] : mAppStats) {
+ GpuStatsApp &gpuStatsApp = gpuStatsApps[index];
+ gpuStatsApp.appStatsKey = &appStatsKey;
+ gpuStatsApp.lastAccessTime = &gpuStatsAppInfo.lastAccessTime;
+ ++index;
+ }
+
+ // Sort the list with the oldest access times at the front.
+ std::sort(gpuStatsApps.begin(), gpuStatsApps.end(), [](GpuStatsApp a, GpuStatsApp b) -> bool {
+ return *a.lastAccessTime < *b.lastAccessTime;
+ });
+
+ // Remove the oldest packages from mAppStats to make room for new apps.
+ for (int i = 0; i < APP_RECORD_HEADROOM; ++i) {
+ mAppStats.erase(*gpuStatsApps[i].appStatsKey);
+ gpuStatsApps[i].appStatsKey = nullptr;
+ gpuStatsApps[i].lastAccessTime = nullptr;
+ }
+}
+
void GpuStats::insertDriverStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
int64_t driverBuildTime, const std::string& appPackageName,
@@ -123,19 +155,22 @@
const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode);
if (!mAppStats.count(appStatsKey)) {
if (mAppStats.size() >= MAX_NUM_APP_RECORDS) {
- ALOGV("GpuStatsAppInfo has reached maximum size. Ignore new stats.");
- return;
+ ALOGV("GpuStatsAppInfo has reached maximum size. Removing old stats to make room.");
+ purgeOldDriverStats();
}
GpuStatsAppInfo appInfo;
addLoadingTime(driver, driverLoadingTime, &appInfo);
appInfo.appPackageName = appPackageName;
appInfo.driverVersionCode = driverVersionCode;
+ appInfo.angleInUse = driverPackageName == "angle";
+ appInfo.lastAccessTime = std::chrono::system_clock::now();
mAppStats.insert({appStatsKey, appInfo});
- return;
+ } else {
+ mAppStats[appStatsKey].angleInUse = driverPackageName == "angle";
+ addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]);
+ mAppStats[appStatsKey].lastAccessTime = std::chrono::system_clock::now();
}
-
- addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]);
}
void GpuStats::insertTargetStats(const std::string& appPackageName,
@@ -311,7 +346,8 @@
angleDriverBytes.length()),
ele.second.cpuVulkanInUse,
ele.second.falsePrerotation,
- ele.second.gles1InUse);
+ ele.second.gles1InUse,
+ ele.second.angleInUse);
}
}
diff --git a/services/gpuservice/gpustats/include/gpustats/GpuStats.h b/services/gpuservice/gpustats/include/gpustats/GpuStats.h
index 55f0da1..2aba651 100644
--- a/services/gpuservice/gpustats/include/gpustats/GpuStats.h
+++ b/services/gpuservice/gpustats/include/gpustats/GpuStats.h
@@ -46,6 +46,11 @@
// This limits the worst case number of loading times tracked.
static const size_t MAX_NUM_LOADING_TIMES = 50;
+ // Below limits the memory usage of GpuStats to be less than 10KB. This is
+ // the preferred number for statsd while maintaining nice data quality.
+ static const size_t MAX_NUM_APP_RECORDS = 100;
+ // The number of apps to remove when mAppStats fills up.
+ static const size_t APP_RECORD_HEADROOM = 10;
private:
// Friend class for testing.
@@ -55,6 +60,10 @@
static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atomTag,
AStatsEventList* data,
void* cookie);
+
+ // Remove old packages from mAppStats.
+ void purgeOldDriverStats();
+
// Pull global into into global atom.
AStatsManager_PullAtomCallbackReturn pullGlobalInfoAtom(AStatsEventList* data);
// Pull app into into app atom.
@@ -68,9 +77,6 @@
// Registers statsd callbacks if they have not already been registered
void registerStatsdCallbacksIfNeeded();
- // Below limits the memory usage of GpuStats to be less than 10KB. This is
- // the preferred number for statsd while maintaining nice data quality.
- static const size_t MAX_NUM_APP_RECORDS = 100;
// GpuStats access should be guarded by mLock.
std::mutex mLock;
// True if statsd callbacks have been registered.
diff --git a/services/gpuservice/tests/unittests/GpuStatsTest.cpp b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
index 37ebeae..20c8ccf 100644
--- a/services/gpuservice/tests/unittests/GpuStatsTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "gpuservice_unittest"
+#include <unistd.h>
#include <cutils/properties.h>
#include <gmock/gmock.h>
#include <gpustats/GpuStats.h>
@@ -221,6 +222,51 @@
EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("gles1InUse = 1"));
}
+// Verify we always have the most recently used apps in mAppStats, even when we fill it.
+TEST_F(GpuStatsTest, canInsertMoreThanMaxNumAppRecords) {
+ constexpr int kNumExtraApps = 15;
+ static_assert(kNumExtraApps > GpuStats::APP_RECORD_HEADROOM);
+
+ // Insert stats for GpuStats::MAX_NUM_APP_RECORDS so we fill it up.
+ for (int i = 0; i < GpuStats::MAX_NUM_APP_RECORDS + kNumExtraApps; ++i) {
+ std::stringstream nameStream;
+ nameStream << "testapp" << "_" << i;
+ std::string fullPkgName = nameStream.str();
+
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME,
+ fullPkgName, VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+ mGpuStats->insertTargetStats(fullPkgName, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::CPU_VULKAN_IN_USE, 0);
+ mGpuStats->insertTargetStats(fullPkgName, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::FALSE_PREROTATION, 0);
+ mGpuStats->insertTargetStats(fullPkgName, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::GLES_1_IN_USE, 0);
+
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(fullPkgName.c_str()));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("cpuVulkanInUse = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("falsePrerotation = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("gles1InUse = 1"));
+ }
+
+ // mAppStats purges GpuStats::APP_RECORD_HEADROOM apps removed everytime it's filled up.
+ int numPurges = kNumExtraApps / GpuStats::APP_RECORD_HEADROOM;
+ numPurges += (kNumExtraApps % GpuStats::APP_RECORD_HEADROOM) == 0 ? 0 : 1;
+
+ // Verify the remaining apps are present.
+ for (int i = numPurges * GpuStats::APP_RECORD_HEADROOM;
+ i < GpuStats::MAX_NUM_APP_RECORDS + kNumExtraApps;
+ ++i) {
+ std::stringstream nameStream;
+ // Add a newline to search for the exact package name.
+ nameStream << "testapp" << "_" << i << "\n";
+ std::string fullPkgName = nameStream.str();
+
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(fullPkgName.c_str()));
+ }
+}
+
TEST_F(GpuStatsTest, canDumpAllBeforeClearAll) {
mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 0b632f7..30f25e5 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -782,12 +782,8 @@
std::optional<int32_t> associatedDisplayId = device->getAssociatedDisplayId();
// No associated display. By default, can dispatch to all displays.
- if (!associatedDisplayId) {
- return true;
- }
-
- if (*associatedDisplayId == ADISPLAY_ID_NONE) {
- ALOGW("Device %s is associated with display ADISPLAY_ID_NONE.", device->getName().c_str());
+ if (!associatedDisplayId ||
+ *associatedDisplayId == ADISPLAY_ID_NONE) {
return true;
}
diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp
index 3663cdb..de8e6b3 100644
--- a/services/surfaceflinger/BackgroundExecutor.cpp
+++ b/services/surfaceflinger/BackgroundExecutor.cpp
@@ -32,7 +32,9 @@
std::vector<std::function<void()>> tasks;
{
std::unique_lock lock(mMutex);
- mWorkAvailableCv.wait(lock, [&]() { return mDone || !mTasks.empty(); });
+ android::base::ScopedLockAssertion assumeLock(mMutex);
+ mWorkAvailableCv.wait(lock,
+ [&]() REQUIRES(mMutex) { return mDone || !mTasks.empty(); });
tasks = std::move(mTasks);
mTasks.clear();
done = mDone;
@@ -47,7 +49,7 @@
BackgroundExecutor::~BackgroundExecutor() {
{
- std::unique_lock lock(mMutex);
+ std::scoped_lock lock(mMutex);
mDone = true;
mWorkAvailableCv.notify_all();
}
@@ -57,7 +59,7 @@
}
void BackgroundExecutor::execute(std::function<void()> task) {
- std::unique_lock lock(mMutex);
+ std::scoped_lock lock(mMutex);
mTasks.emplace_back(std::move(task));
mWorkAvailableCv.notify_all();
}
diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h
index 6f6d305..6db7dda 100644
--- a/services/surfaceflinger/BackgroundExecutor.h
+++ b/services/surfaceflinger/BackgroundExecutor.h
@@ -16,6 +16,7 @@
#pragma once
+#include <android-base/thread_annotations.h>
#include <utils/Singleton.h>
#include <condition_variable>
#include <mutex>
@@ -33,10 +34,10 @@
private:
std::mutex mMutex;
- std::condition_variable mWorkAvailableCv;
+ std::condition_variable mWorkAvailableCv GUARDED_BY(mMutex);
+ bool mDone GUARDED_BY(mMutex) = false;
+ std::vector<std::function<void()>> mTasks GUARDED_BY(mMutex);
std::thread mThread;
- bool mDone = false;
- std::vector<std::function<void()>> mTasks;
};
} // namespace android
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 0a8ebec..6d7b732 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -98,7 +98,8 @@
status_t Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,
int32_t* outLayerId) {
- return mFlinger->mirrorLayer(this, mirrorFromHandle, outHandle, outLayerId);
+ LayerCreationArgs args(mFlinger.get(), this, "MirrorRoot", 0 /* flags */, LayerMetadata());
+ return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId);
}
status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index ac243c0..e77e155 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -134,6 +134,9 @@
// Configure layer settings for using blurs
BlurSetting blurSetting;
+
+ // Requested white point of the layer in nits
+ const float whitePointNits;
};
// A superset of LayerSettings required by RenderEngine to compose a layer
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index a000661..7e605f9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -161,7 +161,7 @@
// The buffer and related state
sp<GraphicBuffer> buffer;
int bufferSlot{BufferQueue::INVALID_BUFFER_SLOT};
- sp<Fence> acquireFence;
+ sp<Fence> acquireFence = Fence::NO_FENCE;
Region surfaceDamage;
// The handle to use for a sideband stream for this layer
@@ -200,6 +200,9 @@
// The output-independent frame for the cursor
Rect cursorFrame;
+ // framerate of the layer as measured by LayerHistory
+ float fps;
+
virtual ~LayerFECompositionState();
// Debugging
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index b407267..3571e11 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -76,7 +76,7 @@
virtual void applyChangedTypesToLayers(const ChangedTypes&);
virtual void applyDisplayRequests(const DisplayRequests&);
virtual void applyLayerRequestsToLayers(const LayerRequests&);
- virtual void applyClientTargetRequests(const ClientTargetProperty&);
+ virtual void applyClientTargetRequests(const ClientTargetProperty&, float whitePointNits);
// Internal
virtual void setConfiguration(const compositionengine::DisplayCreationArgs&);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 44f754f..c5b6443 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -127,6 +127,9 @@
// SDR white point
float sdrWhitePointNits{-1.f};
+ // White point of the client target
+ float clientTargetWhitePointNits{-1.f};
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 244f8ab..c15249d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -73,8 +73,9 @@
void writeOutputIndependentGeometryStateToHWC(HWC2::Layer*, const LayerFECompositionState&,
bool skipLayer);
void writeOutputDependentPerFrameStateToHWC(HWC2::Layer*);
- void writeOutputIndependentPerFrameStateToHWC(HWC2::Layer*, const LayerFECompositionState&,
- bool skipLayer);
+ void writeOutputIndependentPerFrameStateToHWC(
+ HWC2::Layer*, const LayerFECompositionState&,
+ Hwc2::IComposerClient::Composition compositionType, bool skipLayer);
void writeSolidColorStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&, bool skipLayer);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 7564c54..627b80b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -146,6 +146,10 @@
// Timestamp for when the layer is queued for client composition
nsecs_t clientCompositionTimestamp{0};
+
+ // White point of the layer, in nits.
+ static constexpr float kDefaultWhitePointNits = 200.f;
+ float whitePointNits = kDefaultWhitePointNits;
};
} // namespace compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index cff6527..92cc484 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -87,6 +87,13 @@
const bool mEnableHolePunch;
};
+ // Constants not yet backed by a sysprop
+ // CachedSets that contain no more than this many layers may be considered inactive on the basis
+ // of FPS.
+ static constexpr int kNumLayersFpsConsideration = 1;
+ // Frames/Second threshold below which these CachedSets may be considered inactive.
+ static constexpr float kFpsActiveThreshold = 1.f;
+
Flattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables);
void setDisplaySize(ui::Size size) {
@@ -127,21 +134,22 @@
class Builder {
private:
std::vector<CachedSet>::const_iterator mStart;
- std::vector<size_t> mLengths;
+ int32_t mNumSets = 0;
const CachedSet* mHolePunchCandidate = nullptr;
const CachedSet* mBlurringLayer = nullptr;
+ bool mBuilt = false;
public:
// Initializes a Builder a CachedSet to start from.
// This start iterator must be an iterator for mLayers
void init(const std::vector<CachedSet>::const_iterator& start) {
mStart = start;
- mLengths.push_back(start->getLayerCount());
+ mNumSets = 1;
}
// Appends a new CachedSet to the end of the run
// The provided length must be the size of the next sequential CachedSet in layers
- void append(size_t length) { mLengths.push_back(length); }
+ void increment() { mNumSets++; }
// Sets the hole punch candidate for the Run.
void setHolePunchCandidate(const CachedSet* holePunchCandidate) {
@@ -154,19 +162,36 @@
// Builds a Run instance, if a valid Run may be built.
std::optional<Run> validateAndBuild() {
- if (mLengths.size() == 0) {
- return std::nullopt;
- }
- // Runs of length 1 which are hole punch candidates are allowed if the candidate is
- // going to be used.
- if (mLengths.size() == 1 &&
- (!mHolePunchCandidate || !(mHolePunchCandidate->requiresHolePunch()))) {
+ const bool built = mBuilt;
+ mBuilt = true;
+ if (mNumSets <= 0 || built) {
return std::nullopt;
}
+ const bool requiresHolePunch =
+ mHolePunchCandidate && mHolePunchCandidate->requiresHolePunch();
+
+ if (!requiresHolePunch) {
+ // If we don't require a hole punch, then treat solid color layers at the front
+ // to be "cheap", so remove them from the candidate cached set.
+ while (mNumSets > 1 && mStart->getLayerCount() == 1 &&
+ mStart->getFirstLayer().getBuffer() == nullptr) {
+ mStart++;
+ mNumSets--;
+ }
+
+ // Only allow for single cached sets if a hole punch is required. If we're here,
+ // then we don't require a hole punch, so don't build a run.
+ if (mNumSets <= 1) {
+ return std::nullopt;
+ }
+ }
+
return Run(mStart,
- std::reduce(mLengths.cbegin(), mLengths.cend(), 0u,
- [](size_t left, size_t right) { return left + right; }),
+ std::reduce(mStart, mStart + mNumSets, 0u,
+ [](size_t length, const CachedSet& set) {
+ return length + set.getLayerCount();
+ }),
mHolePunchCandidate, mBlurringLayer);
}
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index 5237527..7397c19 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -245,6 +245,7 @@
bool isProtected() const {
return getOutputLayer()->getLayerFE().getCompositionState()->hasProtectedContent;
}
+ float getFps() const { return getOutputLayer()->getLayerFE().getCompositionState()->fps; }
void dump(std::string& result) const;
std::optional<std::string> compare(const LayerState& other) const;
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 02fa49f..4603e6b 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -237,7 +237,8 @@
applyChangedTypesToLayers(changes->changedTypes);
applyDisplayRequests(changes->displayRequests);
applyLayerRequestsToLayers(changes->layerRequests);
- applyClientTargetRequests(changes->clientTargetProperty);
+ applyClientTargetRequests(changes->clientTargetProperty,
+ changes->clientTargetWhitePointNits);
}
// Determine what type of composition we are doing from the final state
@@ -309,12 +310,14 @@
}
}
-void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty) {
+void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty,
+ float whitePointNits) {
if (clientTargetProperty.dataspace == ui::Dataspace::UNKNOWN) {
return;
}
editState().dataspace = clientTargetProperty.dataspace;
+ editState().clientTargetWhitePointNits = whitePointNits;
getRenderSurface()->setBufferDataspace(clientTargetProperty.dataspace);
getRenderSurface()->setBufferPixelFormat(clientTargetProperty.pixelFormat);
}
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 6800004..d503153 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1057,7 +1057,7 @@
clientCompositionDisplay.maxLuminance = outputState.displayBrightnessNits > 0.f
? outputState.displayBrightnessNits
: mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
- clientCompositionDisplay.sdrWhitePointNits = outputState.sdrWhitePointNits;
+ clientCompositionDisplay.targetLuminanceNits = outputState.clientTargetWhitePointNits;
// Compute the global color transform matrix.
if (!outputState.usesDeviceComposition && !getSkipColorTransform()) {
@@ -1217,7 +1217,8 @@
.dataspace = outputDataspace,
.realContentIsVisible = realContentIsVisible,
.clearContent = !clientComposition,
- .blurSetting = blurSetting};
+ .blurSetting = blurSetting,
+ .whitePointNits = layerState.whitePointNits};
results = layerFE.prepareClientCompositionList(targetSettings);
if (realContentIsVisible && !results.empty()) {
layer->editState().clientCompositionTimestamp = systemTime();
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index e958549..b010d9f 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -24,6 +24,9 @@
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <cstdint>
+#include "system/graphics-base-v1.0.h"
+
+#include <ui/DataspaceUtils.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
@@ -317,6 +320,14 @@
? outputState.targetDataspace
: layerFEState->dataspace;
+ // For hdr content, treat the white point as the display brightness - HDR content should not be
+ // boosted or dimmed.
+ if (isHdrDataspace(state.dataspace)) {
+ state.whitePointNits = getOutput().getState().displayBrightnessNits;
+ } else {
+ state.whitePointNits = getOutput().getState().sdrWhitePointNits;
+ }
+
// These are evaluated every frame as they can potentially change at any
// time.
if (layerFEState->forceClientComposition || !profile.isDataspaceSupported(state.dataspace) ||
@@ -347,6 +358,10 @@
auto requestedCompositionType = outputIndependentState->compositionType;
+ if (requestedCompositionType == hal::Composition::SOLID_COLOR && state.overrideInfo.buffer) {
+ requestedCompositionType = hal::Composition::DEVICE;
+ }
+
// TODO(b/181172795): We now update geometry for all flattened layers. We should update it
// only when the geometry actually changes
const bool isOverridden =
@@ -359,13 +374,15 @@
}
writeOutputDependentPerFrameStateToHWC(hwcLayer.get());
- writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), *outputIndependentState, skipLayer);
+ writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), *outputIndependentState,
+ requestedCompositionType, skipLayer);
writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough,
skipLayer);
- // Always set the layer color after setting the composition type.
- writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState);
+ if (requestedCompositionType == hal::Composition::SOLID_COLOR) {
+ writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState);
+ }
editState().hwc->stateOverridden = isOverridden;
editState().hwc->layerSkipped = skipLayer;
@@ -473,11 +490,21 @@
ALOGE("[%s] Failed to set dataspace %d: %s (%d)", getLayerFE().getDebugName(), dataspace,
to_string(error).c_str(), static_cast<int32_t>(error));
}
+
+ // Don't dim cached layers
+ const auto whitePointNits = outputDependentState.overrideInfo.buffer
+ ? getOutput().getState().displayBrightnessNits
+ : outputDependentState.whitePointNits;
+
+ if (auto error = hwcLayer->setWhitePointNits(whitePointNits); error != hal::Error::NONE) {
+ ALOGE("[%s] Failed to set white point %f: %s (%d)", getLayerFE().getDebugName(),
+ whitePointNits, to_string(error).c_str(), static_cast<int32_t>(error));
+ }
}
void OutputLayer::writeOutputIndependentPerFrameStateToHWC(
HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState,
- bool skipLayer) {
+ hal::Composition compositionType, bool skipLayer) {
switch (auto error = hwcLayer->setColorTransform(outputIndependentState.colorTransform)) {
case hal::Error::NONE:
break;
@@ -501,7 +528,7 @@
}
// Content-specific per-frame state
- switch (outputIndependentState.compositionType) {
+ switch (compositionType) {
case hal::Composition::SOLID_COLOR:
// For compatibility, should be written AFTER the composition type.
break;
@@ -521,10 +548,6 @@
void OutputLayer::writeSolidColorStateToHWC(HWC2::Layer* hwcLayer,
const LayerFECompositionState& outputIndependentState) {
- if (outputIndependentState.compositionType != hal::Composition::SOLID_COLOR) {
- return;
- }
-
hal::Color color = {static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.r)),
static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.g)),
static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.b)),
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index ff96d94..2203f22 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -170,6 +170,7 @@
.clip = viewport,
.outputDataspace = outputDataspace,
.orientation = orientation,
+ .targetLuminanceNits = outputState.displayBrightnessNits,
};
LayerFE::ClientCompositionTargetSettings targetSettings{
@@ -182,6 +183,7 @@
.realContentIsVisible = true,
.clearContent = false,
.blurSetting = LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ .whitePointNits = outputState.displayBrightnessNits,
};
std::vector<renderengine::LayerSettings> layerSettings;
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 2272099..c14effc 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -409,25 +409,29 @@
bool runHasFirstLayer = false;
for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) {
- const bool layerIsInactive =
- now - currentSet->getLastUpdate() > mTunables.mActiveLayerTimeout;
+ bool layerIsInactive = now - currentSet->getLastUpdate() > mTunables.mActiveLayerTimeout;
const bool layerHasBlur = currentSet->hasBlurBehind();
+ // Layers should also be considered inactive whenever their framerate is lower than 1fps.
+ if (!layerIsInactive && currentSet->getLayerCount() == kNumLayersFpsConsideration) {
+ auto layerFps = currentSet->getFirstLayer().getState()->getFps();
+ if (layerFps > 0 && layerFps <= kFpsActiveThreshold) {
+ ATRACE_FORMAT("layer is considered inactive due to low FPS [%s] %f",
+ currentSet->getFirstLayer().getName().c_str(), layerFps);
+ layerIsInactive = true;
+ }
+ }
+
if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) &&
!currentSet->hasUnsupportedDataspace()) {
if (isPartOfRun) {
- builder.append(currentSet->getLayerCount());
+ builder.increment();
} else {
- // Runs can't start with a non-buffer layer
- if (currentSet->getFirstLayer().getBuffer() == nullptr) {
- ALOGV("[%s] Skipping initial non-buffer layer", __func__);
- } else {
- builder.init(currentSet);
- if (firstLayer) {
- runHasFirstLayer = true;
- }
- isPartOfRun = true;
+ builder.init(currentSet);
+ if (firstLayer) {
+ runHasFirstLayer = true;
}
+ isPartOfRun = true;
}
} else if (isPartOfRun) {
builder.setHolePunchCandidate(&(*currentSet));
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index ed235b8..568efce 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -596,6 +596,7 @@
hal::DisplayRequest::FLIP_CLIENT_TARGET,
{{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}},
{hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN},
+ -1.f,
};
// Since two calls are made to anyLayersRequireClientComposition with different return
@@ -788,15 +789,18 @@
.dataspace = hal::Dataspace::STANDARD_BT470M,
};
+ static constexpr float kWhitePointNits = 800.f;
+
mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
mDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
EXPECT_CALL(*renderSurface, setBufferPixelFormat(clientTargetProperty.pixelFormat));
EXPECT_CALL(*renderSurface, setBufferDataspace(clientTargetProperty.dataspace));
- mDisplay->applyClientTargetRequests(clientTargetProperty);
+ mDisplay->applyClientTargetRequests(clientTargetProperty, kWhitePointNits);
auto& state = mDisplay->getState();
EXPECT_EQ(clientTargetProperty.dataspace, state.dataspace);
+ EXPECT_EQ(kWhitePointNits, state.clientTargetWhitePointNits);
}
/*
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index 9518659..9e08f9e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -71,6 +71,7 @@
MOCK_METHOD1(setColorTransform, Error(const android::mat4&));
MOCK_METHOD3(setLayerGenericMetadata,
Error(const std::string&, bool, const std::vector<uint8_t>&));
+ MOCK_METHOD1(setWhitePointNits, Error(float));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index fbc2089..207c31e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -652,6 +652,22 @@
EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace);
}
+TEST_F(OutputLayerUpdateCompositionStateTest, setsWhitePointNitsCorrectly) {
+ mOutputState.sdrWhitePointNits = 200.f;
+ mOutputState.displayBrightnessNits = 800.f;
+
+ mLayerFEState.dataspace = ui::Dataspace::DISPLAY_P3;
+ mLayerFEState.isColorspaceAgnostic = false;
+ mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
+ EXPECT_EQ(mOutputState.sdrWhitePointNits, mOutputLayer.getState().whitePointNits);
+
+ mLayerFEState.dataspace = ui::Dataspace::BT2020_ITU_PQ;
+ mLayerFEState.isColorspaceAgnostic = false;
+ mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0);
+
+ EXPECT_EQ(mOutputState.displayBrightnessNits, mOutputLayer.getState().whitePointNits);
+}
+
TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) {
mOutputLayer.editState().forceClientComposition = false;
@@ -728,6 +744,8 @@
static constexpr int kOverrideHwcSlot = impl::HwcBufferCache::FLATTENER_CACHING_SLOT;
static constexpr bool kLayerGenericMetadata1Mandatory = true;
static constexpr bool kLayerGenericMetadata2Mandatory = true;
+ static constexpr float kWhitePointNits = 200.f;
+ static constexpr float kDisplayBrightnessNits = 400.f;
static const half4 kColor;
static const Rect kDisplayFrame;
@@ -758,6 +776,7 @@
outputLayerState.bufferTransform = static_cast<Hwc2::Transform>(kBufferTransform);
outputLayerState.outputSpaceVisibleRegion = kOutputSpaceVisibleRegion;
outputLayerState.dataspace = kDataspace;
+ outputLayerState.whitePointNits = kWhitePointNits;
mLayerFEState.blendMode = kBlendMode;
mLayerFEState.alpha = kAlpha;
@@ -770,6 +789,8 @@
mLayerFEState.bufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
mLayerFEState.acquireFence = kFence;
+ mOutputState.displayBrightnessNits = kDisplayBrightnessNits;
+
EXPECT_CALL(mOutput, getDisplayColorProfile())
.WillRepeatedly(Return(&mDisplayColorProfile));
EXPECT_CALL(mDisplayColorProfile, getSupportedPerFrameMetadata())
@@ -818,9 +839,11 @@
void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None,
ui::Dataspace dataspace = kDataspace,
const Region& visibleRegion = kOutputSpaceVisibleRegion,
- const Region& surfaceDamage = kSurfaceDamage) {
+ const Region& surfaceDamage = kSurfaceDamage,
+ float whitePointNits = kWhitePointNits) {
EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(visibleRegion))).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setDataspace(dataspace)).WillOnce(Return(kError));
+ EXPECT_CALL(*mHwcLayer, setWhitePointNits(whitePointNits)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform))
.WillOnce(Return(unsupported == SimulateUnsupported::ColorTransform
? hal::Error::UNSUPPORTED
@@ -1084,7 +1107,23 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kSkipAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage);
+ kOverrideSurfaceDamage, kDisplayBrightnessNits);
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerForSolidColorDoesNotSendBuffer) {
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+ includeOverrideInfo();
+
+ expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
+ kOverrideBlendMode, kSkipAlpha);
+ expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
+ kOverrideSurfaceDamage, kDisplayBrightnessNits);
expectSetHdrMetadataAndBufferCalls();
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
@@ -1100,7 +1139,23 @@
expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
kOverrideBlendMode, kOverrideAlpha);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
- kOverrideSurfaceDamage);
+ kOverrideSurfaceDamage, kDisplayBrightnessNits);
+ expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoForSolidColorIfPresent) {
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+ includeOverrideInfo();
+
+ expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideSourceCrop, kOverrideBufferTransform,
+ kOverrideBlendMode, kOverrideAlpha);
+ expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
+ kOverrideSurfaceDamage, kDisplayBrightnessNits);
expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index cf63ef5..6d96260 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3023,6 +3023,7 @@
mOutput.mState.usesDeviceComposition = false;
mOutput.mState.reusedClientComposition = false;
mOutput.mState.flipClientTarget = false;
+ mOutput.mState.clientTargetWhitePointNits = kClientTargetLuminanceNits;
EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine));
EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
@@ -3057,6 +3058,7 @@
static constexpr float kDefaultMaxLuminance = 0.9f;
static constexpr float kDefaultAvgLuminance = 0.7f;
static constexpr float kDefaultMinLuminance = 0.1f;
+ static constexpr float kClientTargetLuminanceNits = 200.f;
static const Rect kDefaultOutputFrame;
static const Rect kDefaultOutputViewport;
@@ -3424,7 +3426,8 @@
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- kDefaultOutputOrientationFlags})
+ kDefaultOutputOrientationFlags,
+ kClientTargetLuminanceNits})
.execute()
.expectAFenceWasReturned();
}
@@ -3435,7 +3438,8 @@
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- kDefaultOutputOrientationFlags})
+ kDefaultOutputOrientationFlags,
+ kClientTargetLuminanceNits})
.execute()
.expectAFenceWasReturned();
}
@@ -3444,10 +3448,10 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
- kDefaultMaxLuminance, kDefaultOutputDataspace,
- kDefaultColorTransformMat,
- kDefaultOutputOrientationFlags})
+ .thenExpectDisplaySettingsUsed(
+ {kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance,
+ kDefaultOutputDataspace, kDefaultColorTransformMat,
+ kDefaultOutputOrientationFlags, kClientTargetLuminanceNits})
.execute()
.expectAFenceWasReturned();
}
@@ -3456,10 +3460,10 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(false)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
- kDefaultMaxLuminance, kDefaultOutputDataspace,
- kDefaultColorTransformMat,
- kDefaultOutputOrientationFlags})
+ .thenExpectDisplaySettingsUsed(
+ {kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance,
+ kDefaultOutputDataspace, kDefaultColorTransformMat,
+ kDefaultOutputOrientationFlags, kClientTargetLuminanceNits})
.execute()
.expectAFenceWasReturned();
}
@@ -3471,7 +3475,8 @@
.andIfSkipColorTransform(true)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- kDefaultOutputOrientationFlags})
+ kDefaultOutputOrientationFlags,
+ kClientTargetLuminanceNits})
.execute()
.expectAFenceWasReturned();
}
@@ -3729,6 +3734,8 @@
mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
}
+ static constexpr float kLayerWhitePointNits = 200.f;
+
mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
StrictMock<OutputPartialMock> mOutput;
@@ -3768,6 +3775,7 @@
static constexpr ui::Rotation kDisplayOrientation = ui::ROTATION_0;
static constexpr ui::Dataspace kDisplayDataspace = ui::Dataspace::UNKNOWN;
+ static constexpr float kLayerWhitePointNits = 200.f;
static const Rect kDisplayFrame;
static const Rect kDisplayViewport;
@@ -3930,14 +3938,15 @@
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
- false, /* needs filtering */
- false, /* secure */
- false, /* supports protected content */
+ false, /* needs filtering */
+ false, /* secure */
+ false, /* supports protected content */
kDisplayViewport,
kDisplayDataspace,
false /* realContentIsVisible */,
true /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(kDisplayFrame),
@@ -3949,6 +3958,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
LayerFE::LayerSettings mBlackoutSettings = mLayers[1].mLayerSettings;
@@ -3988,6 +3998,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(Rect(0, 0, 30, 30)),
@@ -3999,6 +4010,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(Rect(0, 0, 40, 201)),
@@ -4010,6 +4022,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
@@ -4039,6 +4052,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
@@ -4050,6 +4064,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(kDisplayFrame),
@@ -4061,6 +4076,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
@@ -4090,7 +4106,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
-
+ kLayerWhitePointNits,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
@@ -4102,6 +4118,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(kDisplayFrame),
@@ -4113,6 +4130,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
@@ -4141,6 +4159,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
@@ -4152,6 +4171,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(kDisplayFrame),
@@ -4163,6 +4183,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
@@ -4179,7 +4200,6 @@
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
protectedContentSupportUsedToGenerateRequests) {
-
compositionengine::LayerFE::ClientCompositionTargetSettings layer0TargetSettings{
Region(kDisplayFrame),
false, /* needs filtering */
@@ -4190,6 +4210,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
@@ -4201,6 +4222,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(kDisplayFrame),
@@ -4212,6 +4234,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
@@ -4379,6 +4402,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
EXPECT_CALL(leftLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
@@ -4396,6 +4420,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
EXPECT_CALL(rightLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
@@ -4428,6 +4453,7 @@
false /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
LayerFE::LayerSettings mShadowSettings;
@@ -4472,6 +4498,7 @@
true /* realContentIsVisible */,
false /* clearContent */,
compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
+ kLayerWhitePointNits,
};
EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 42b3d97..d5a117a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -55,13 +55,21 @@
}
MATCHER_P(ClientCompositionTargetSettingsSecureEq, expectedSecureSetting, "") {
- *result_listener << "ClientCompositionTargetSettings' SecureSettings aren't equal \n";
+ *result_listener << "ClientCompositionTargetSettings' isSecure bits aren't equal \n";
*result_listener << "expected " << expectedSecureSetting << "\n";
*result_listener << "actual " << arg.isSecure << "\n";
return expectedSecureSetting == arg.isSecure;
}
+MATCHER_P(ClientCompositionTargetSettingsWhitePointEq, expectedWhitePoint, "") {
+ *result_listener << "ClientCompositionTargetSettings' white points aren't equal \n";
+ *result_listener << "expected " << expectedWhitePoint << "\n";
+ *result_listener << "actual " << arg.whitePointNits << "\n";
+
+ return expectedWhitePoint == arg.whitePointNits;
+}
+
static const ui::Size kOutputSize = ui::Size(1, 1);
class CachedSetTest : public testing::Test {
@@ -431,6 +439,54 @@
cachedSet.append(CachedSet(layer3));
}
+TEST_F(CachedSetTest, renderWhitePoint) {
+ // Skip the 0th layer to ensure that the bounding box of the layers is offset from (0, 0)
+ CachedSet::Layer& layer1 = *mTestLayers[1]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE1 = mTestLayers[1]->layerFE;
+ CachedSet::Layer& layer2 = *mTestLayers[2]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE2 = mTestLayers[2]->layerFE;
+
+ CachedSet cachedSet(layer1);
+ cachedSet.append(CachedSet(layer2));
+
+ std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1;
+ clientCompList1.push_back({});
+
+ std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2;
+ clientCompList2.push_back({});
+
+ mOutputState.displayBrightnessNits = 400.f;
+
+ const auto drawLayers =
+ [&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<renderengine::LayerSettings>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd&&) -> std::future<renderengine::RenderEngineResult> {
+ EXPECT_EQ(mOutputState.displayBrightnessNits, displaySettings.targetLuminanceNits);
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+ };
+
+ EXPECT_CALL(*layerFE1,
+ prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq(
+ mOutputState.displayBrightnessNits)))
+ .WillOnce(Return(clientCompList1));
+ EXPECT_CALL(*layerFE2,
+ prepareClientCompositionList(ClientCompositionTargetSettingsWhitePointEq(
+ mOutputState.displayBrightnessNits)))
+ .WillOnce(Return(clientCompList2));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ mOutputState.isSecure = true;
+ cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
+ expectReadyBuffer(cachedSet);
+
+ EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
+ EXPECT_EQ(Rect(kOutputSize.width, kOutputSize.height), cachedSet.getTextureBounds());
+
+ // Now check that appending a new cached set properly cleans up RenderEngine resources.
+ CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+ cachedSet.append(CachedSet(layer3));
+}
+
TEST_F(CachedSetTest, rendersWithOffsetFramebufferContent) {
// Skip the 0th layer to ensure that the bounding box of the layers is offset from (0, 0)
CachedSet::Layer& layer1 = *mTestLayers[1]->cachedSetLayer.get();
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 9b0a75f..35d051e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -224,6 +224,22 @@
mFlattener->renderCachedSets(mOutputState, std::nullopt);
}
+TEST_F(FlattenerTest, flattenLayers_ActiveLayersWithLowFpsAreFlattened) {
+ mTestLayers[0]->layerFECompositionState.fps = Flattener::kFpsActiveThreshold / 2;
+ mTestLayers[1]->layerFECompositionState.fps = Flattener::kFpsActiveThreshold;
+
+ auto& layerState1 = mTestLayers[0]->layerState;
+ auto& layerState2 = mTestLayers[1]->layerState;
+
+ const std::vector<const LayerState*> layers = {
+ layerState1.get(),
+ layerState2.get(),
+ };
+
+ initializeFlattener(layers);
+ expectAllLayersFlattened(layers);
+}
+
TEST_F(FlattenerTest, flattenLayers_basicFlatten) {
auto& layerState1 = mTestLayers[0]->layerState;
auto& layerState2 = mTestLayers[1]->layerState;
@@ -746,6 +762,76 @@
EXPECT_EQ(nullptr, peekThroughLayer1);
}
+TEST_F(FlattenerTest, flattenLayers_holePunchSingleColorLayer) {
+ mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5);
+ mTestLayers[0]->layerFECompositionState.color = half4(255.f, 0.f, 0.f, 255.f);
+ mTestLayers[0]->layerFECompositionState.buffer = nullptr;
+
+ // An opaque static background
+ auto& layerState0 = mTestLayers[0]->layerState;
+ const auto& overrideBuffer0 = layerState0->getOutputLayer()->getState().overrideInfo.buffer;
+
+ // a rounded updating layer
+ auto& layerState1 = mTestLayers[1]->layerState;
+ const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
+
+ EXPECT_CALL(*mTestLayers[1]->layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
+
+ std::vector<LayerFE::LayerSettings> clientCompositionList = {
+ LayerFE::LayerSettings{},
+ };
+ clientCompositionList[0].source.buffer.buffer = std::make_shared<
+ renderengine::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer,
+ mRenderEngine,
+ renderengine::ExternalTexture::Usage::READABLE);
+ EXPECT_CALL(*mTestLayers[1]->layerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(clientCompositionList));
+
+ const std::vector<const LayerState*> layers = {
+ layerState0.get(),
+ layerState1.get(),
+ };
+
+ initializeFlattener(layers);
+
+ // layer 1 satisfies every condition in CachedSet::requiresHolePunch()
+ mTime += 200ms;
+ layerState1->resetFramesSinceBufferUpdate(); // it is updating
+
+ initializeOverrideBuffer(layers);
+ // Expect no cache invalidation the first time (there's no cache yet)
+ EXPECT_EQ(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+
+ // This will render a CachedSet of layer 0. Though it is just one layer, it satisfies the
+ // exception that there would be a hole punch above it.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+ mFlattener->renderCachedSets(mOutputState, std::nullopt);
+
+ // We've rendered a CachedSet, but we haven't merged it in.
+ EXPECT_EQ(nullptr, overrideBuffer0);
+
+ // This time we merge the CachedSet in and we should still have only two sets.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
+ initializeOverrideBuffer(layers);
+ EXPECT_EQ(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+ mFlattener->renderCachedSets(mOutputState, std::nullopt);
+
+ EXPECT_NE(nullptr, overrideBuffer0); // got overridden
+ EXPECT_EQ(nullptr, overrideBuffer1); // did not
+
+ // expect 0's peek though layer to be 1's output layer
+ const auto* peekThroughLayer0 =
+ layerState0->getOutputLayer()->getState().overrideInfo.peekThroughLayer;
+ const auto* peekThroughLayer1 =
+ layerState1->getOutputLayer()->getState().overrideInfo.peekThroughLayer;
+ EXPECT_EQ(&mTestLayers[1]->outputLayer, peekThroughLayer0);
+ EXPECT_EQ(nullptr, peekThroughLayer1);
+}
+
TEST_F(FlattenerTest, flattenLayers_flattensBlurBehindRunIfFirstRun) {
auto& layerState1 = mTestLayers[0]->layerState;
@@ -1191,5 +1277,61 @@
EXPECT_EQ(nullptr, overrideBuffer3);
}
+TEST_F(FlattenerTest, flattenLayers_skipsColorLayers) {
+ auto& layerState1 = mTestLayers[0]->layerState;
+ const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
+ auto& layerState2 = mTestLayers[1]->layerState;
+ const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer;
+ auto& layerState3 = mTestLayers[2]->layerState;
+ const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer;
+ auto& layerState4 = mTestLayers[3]->layerState;
+ const auto& overrideBuffer4 = layerState4->getOutputLayer()->getState().overrideInfo.buffer;
+
+ // Rewrite the first two layers to just be a solid color.
+ mTestLayers[0]->layerFECompositionState.color = half4(255.f, 0.f, 0.f, 255.f);
+ mTestLayers[0]->layerFECompositionState.buffer = nullptr;
+ mTestLayers[1]->layerFECompositionState.color = half4(0.f, 255.f, 0.f, 255.f);
+ mTestLayers[1]->layerFECompositionState.buffer = nullptr;
+
+ const std::vector<const LayerState*> layers = {
+ layerState1.get(),
+ layerState2.get(),
+ layerState3.get(),
+ layerState4.get(),
+ };
+
+ initializeFlattener(layers);
+
+ mTime += 200ms;
+ initializeOverrideBuffer(layers);
+ EXPECT_EQ(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+
+ // This will render a CachedSet.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+ mFlattener->renderCachedSets(mOutputState, std::nullopt);
+
+ // We've rendered a CachedSet, but we haven't merged it in.
+ EXPECT_EQ(nullptr, overrideBuffer1);
+ EXPECT_EQ(nullptr, overrideBuffer2);
+ EXPECT_EQ(nullptr, overrideBuffer3);
+ EXPECT_EQ(nullptr, overrideBuffer4);
+
+ // This time we merge the CachedSet in, so we have a new hash, and we should
+ // only have two sets.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
+ initializeOverrideBuffer(layers);
+ EXPECT_NE(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+ mFlattener->renderCachedSets(mOutputState, std::nullopt);
+
+ EXPECT_EQ(nullptr, overrideBuffer1);
+ EXPECT_EQ(nullptr, overrideBuffer2);
+ EXPECT_EQ(overrideBuffer3, overrideBuffer4);
+ EXPECT_NE(nullptr, overrideBuffer4);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index ba57be5..29e5a74 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -41,6 +41,8 @@
using aidl::android::hardware::graphics::composer3::PowerMode;
using aidl::android::hardware::graphics::composer3::VirtualDisplay;
+using aidl::android::hardware::graphics::composer3::command::CommandResultPayload;
+
using AidlColorMode = aidl::android::hardware::graphics::composer3::ColorMode;
using AidlContentType = aidl::android::hardware::graphics::composer3::ContentType;
using AidlDisplayIdentification =
@@ -48,8 +50,6 @@
using AidlDisplayContentSample = aidl::android::hardware::graphics::composer3::DisplayContentSample;
using AidlDisplayAttribute = aidl::android::hardware::graphics::composer3::DisplayAttribute;
using AidlDisplayCapability = aidl::android::hardware::graphics::composer3::DisplayCapability;
-using AidlExecuteCommandsStatus =
- aidl::android::hardware::graphics::composer3::ExecuteCommandsStatus;
using AidlHdrCapabilities = aidl::android::hardware::graphics::composer3::HdrCapabilities;
using AidlPerFrameMetadata = aidl::android::hardware::graphics::composer3::PerFrameMetadata;
using AidlPerFrameMetadataKey = aidl::android::hardware::graphics::composer3::PerFrameMetadataKey;
@@ -174,6 +174,14 @@
};
}
+template <>
+IComposerClient::ClientTargetProperty translate(ClientTargetProperty x) {
+ return IComposerClient::ClientTargetProperty{
+ .pixelFormat = translate<PixelFormat>(x.pixelFormat),
+ .dataspace = translate<Dataspace>(x.dataspace),
+ };
+}
+
mat4 makeMat4(std::vector<float> in) {
return mat4(static_cast<const float*>(in.data()));
}
@@ -226,7 +234,7 @@
return AServiceManager_isDeclared(instance(serviceName).c_str());
}
-AidlComposer::AidlComposer(const std::string& serviceName) : mWriter(kWriterInitialSize) {
+AidlComposer::AidlComposer(const std::string& serviceName) {
// This only waits if the service is actually declared
mAidlComposer = AidlIComposer::fromBinder(
ndk::SpAIBinder(AServiceManager_waitForService(instance(serviceName).c_str())));
@@ -327,8 +335,7 @@
}
Error AidlComposer::acceptDisplayChanges(Display display) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.acceptDisplayChanges();
+ mWriter.acceptDisplayChanges(translate<int64_t>(display));
return Error::NONE;
}
@@ -369,7 +376,12 @@
Error AidlComposer::getChangedCompositionTypes(
Display display, std::vector<Layer>* outLayers,
std::vector<IComposerClient::Composition>* outTypes) {
- mReader.takeChangedCompositionTypes(display, outLayers, outTypes);
+ std::vector<int64_t> layers;
+ std::vector<Composition> types;
+ mReader.takeChangedCompositionTypes(translate<int64_t>(display), &layers, &types);
+
+ *outLayers = translate<Layer>(layers);
+ *outTypes = translate<IComposerClient::Composition>(types);
return Error::NONE;
}
@@ -422,7 +434,10 @@
Error AidlComposer::getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
std::vector<Layer>* outLayers,
std::vector<uint32_t>* outLayerRequestMasks) {
- mReader.takeDisplayRequests(display, outDisplayRequestMask, outLayers, outLayerRequestMasks);
+ std::vector<int64_t> layers;
+ mReader.takeDisplayRequests(translate<int64_t>(display), outDisplayRequestMask, &layers,
+ outLayerRequestMasks);
+ *outLayers = translate<Layer>(layers);
return Error::NONE;
}
@@ -456,21 +471,22 @@
Error AidlComposer::getReleaseFences(Display display, std::vector<Layer>* outLayers,
std::vector<int>* outReleaseFences) {
- mReader.takeReleaseFences(display, outLayers, outReleaseFences);
+ std::vector<int64_t> layers;
+ mReader.takeReleaseFences(translate<int64_t>(display), &layers, outReleaseFences);
+ *outLayers = translate<Layer>(layers);
return Error::NONE;
}
Error AidlComposer::presentDisplay(Display display, int* outPresentFence) {
ATRACE_NAME("HwcPresentDisplay");
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.presentDisplay();
+ mWriter.presentDisplay(translate<int64_t>(display));
Error error = execute();
if (error != Error::NONE) {
return error;
}
- mReader.takePresentFence(display, outPresentFence);
+ mReader.takePresentFence(translate<int64_t>(display), outPresentFence);
return Error::NONE;
}
@@ -488,14 +504,12 @@
Error AidlComposer::setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
int acquireFence, Dataspace dataspace,
const std::vector<IComposerClient::Rect>& damage) {
- mWriter.selectDisplay(translate<int64_t>(display));
-
const native_handle_t* handle = nullptr;
if (target.get()) {
handle = target->getNativeBuffer()->handle;
}
- mWriter.setClientTarget(slot, handle, acquireFence,
+ mWriter.setClientTarget(translate<int64_t>(display), slot, handle, acquireFence,
translate<aidl::android::hardware::graphics::common::Dataspace>(
dataspace),
translate<AidlRect>(damage));
@@ -515,15 +529,14 @@
}
Error AidlComposer::setColorTransform(Display display, const float* matrix, ColorTransform hint) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.setColorTransform(matrix, translate<AidlColorTransform>(hint));
+ mWriter.setColorTransform(translate<int64_t>(display), matrix,
+ translate<AidlColorTransform>(hint));
return Error::NONE;
}
Error AidlComposer::setOutputBuffer(Display display, const native_handle_t* buffer,
int releaseFence) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.setOutputBuffer(0, buffer, dup(releaseFence));
+ mWriter.setOutputBuffer(translate<int64_t>(display), 0, buffer, dup(releaseFence));
return Error::NONE;
}
@@ -562,15 +575,14 @@
Error AidlComposer::validateDisplay(Display display, uint32_t* outNumTypes,
uint32_t* outNumRequests) {
ATRACE_NAME("HwcValidateDisplay");
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.validateDisplay();
+ mWriter.validateDisplay(translate<int64_t>(display));
Error error = execute();
if (error != Error::NONE) {
return error;
}
- mReader.hasChanges(display, outNumTypes, outNumRequests);
+ mReader.hasChanges(translate<int64_t>(display), outNumTypes, outNumRequests);
return Error::NONE;
}
@@ -579,207 +591,154 @@
uint32_t* outNumRequests, int* outPresentFence,
uint32_t* state) {
ATRACE_NAME("HwcPresentOrValidateDisplay");
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.presentOrvalidateDisplay();
+ mWriter.presentOrvalidateDisplay(translate<int64_t>(display));
Error error = execute();
if (error != Error::NONE) {
return error;
}
- mReader.takePresentOrValidateStage(display, state);
+ mReader.takePresentOrValidateStage(translate<int64_t>(display), state);
if (*state == 1) { // Present succeeded
- mReader.takePresentFence(display, outPresentFence);
+ mReader.takePresentFence(translate<int64_t>(display), outPresentFence);
}
if (*state == 0) { // Validate succeeded.
- mReader.hasChanges(display, outNumTypes, outNumRequests);
+ mReader.hasChanges(translate<int64_t>(display), outNumTypes, outNumRequests);
}
return Error::NONE;
}
Error AidlComposer::setCursorPosition(Display display, Layer layer, int32_t x, int32_t y) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerCursorPosition(x, y);
+ mWriter.setLayerCursorPosition(translate<int64_t>(display), translate<int64_t>(layer), x, y);
return Error::NONE;
}
Error AidlComposer::setLayerBuffer(Display display, Layer layer, uint32_t slot,
const sp<GraphicBuffer>& buffer, int acquireFence) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
-
const native_handle_t* handle = nullptr;
if (buffer.get()) {
handle = buffer->getNativeBuffer()->handle;
}
- mWriter.setLayerBuffer(slot, handle, acquireFence);
+ mWriter.setLayerBuffer(translate<int64_t>(display), translate<int64_t>(layer), slot, handle,
+ acquireFence);
return Error::NONE;
}
Error AidlComposer::setLayerSurfaceDamage(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& damage) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerSurfaceDamage(translate<AidlRect>(damage));
+ mWriter.setLayerSurfaceDamage(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlRect>(damage));
return Error::NONE;
}
Error AidlComposer::setLayerBlendMode(Display display, Layer layer,
IComposerClient::BlendMode mode) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerBlendMode(translate<BlendMode>(mode));
+ mWriter.setLayerBlendMode(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<BlendMode>(mode));
return Error::NONE;
}
Error AidlComposer::setLayerColor(Display display, Layer layer,
const IComposerClient::Color& color) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerColor(translate<Color>(color));
+ mWriter.setLayerColor(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<Color>(color));
return Error::NONE;
}
Error AidlComposer::setLayerCompositionType(Display display, Layer layer,
IComposerClient::Composition type) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerCompositionType(translate<Composition>(type));
+ mWriter.setLayerCompositionType(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<Composition>(type));
return Error::NONE;
}
Error AidlComposer::setLayerDataspace(Display display, Layer layer, Dataspace dataspace) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerDataspace(translate<AidlDataspace>(dataspace));
+ mWriter.setLayerDataspace(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlDataspace>(dataspace));
return Error::NONE;
}
Error AidlComposer::setLayerDisplayFrame(Display display, Layer layer,
const IComposerClient::Rect& frame) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerDisplayFrame(translate<AidlRect>(frame));
+ mWriter.setLayerDisplayFrame(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlRect>(frame));
return Error::NONE;
}
Error AidlComposer::setLayerPlaneAlpha(Display display, Layer layer, float alpha) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerPlaneAlpha(alpha);
+ mWriter.setLayerPlaneAlpha(translate<int64_t>(display), translate<int64_t>(layer), alpha);
return Error::NONE;
}
Error AidlComposer::setLayerSidebandStream(Display display, Layer layer,
const native_handle_t* stream) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerSidebandStream(stream);
+ mWriter.setLayerSidebandStream(translate<int64_t>(display), translate<int64_t>(layer), stream);
return Error::NONE;
}
Error AidlComposer::setLayerSourceCrop(Display display, Layer layer,
const IComposerClient::FRect& crop) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerSourceCrop(translate<AidlFRect>(crop));
+ mWriter.setLayerSourceCrop(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlFRect>(crop));
return Error::NONE;
}
Error AidlComposer::setLayerTransform(Display display, Layer layer, Transform transform) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerTransform(translate<AidlTransform>(transform));
+ mWriter.setLayerTransform(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlTransform>(transform));
return Error::NONE;
}
Error AidlComposer::setLayerVisibleRegion(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& visible) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerVisibleRegion(translate<AidlRect>(visible));
+ mWriter.setLayerVisibleRegion(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlRect>(visible));
return Error::NONE;
}
Error AidlComposer::setLayerZOrder(Display display, Layer layer, uint32_t z) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerZOrder(z);
+ mWriter.setLayerZOrder(translate<int64_t>(display), translate<int64_t>(layer), z);
return Error::NONE;
}
Error AidlComposer::execute() {
- // prepare input command queue
- bool queueChanged = false;
- int32_t commandLength = 0;
- std::vector<aidl::android::hardware::common::NativeHandle> commandHandles;
- if (!mWriter.writeQueue(&queueChanged, &commandLength, &commandHandles)) {
- mWriter.reset();
- return Error::NO_RESOURCES;
- }
-
- // set up new input command queue if necessary
- if (queueChanged) {
- const auto status = mAidlComposerClient->setInputCommandQueue(mWriter.getMQDescriptor());
- if (!status.isOk()) {
- ALOGE("setInputCommandQueue failed %s", status.getDescription().c_str());
- mWriter.reset();
- return static_cast<Error>(status.getServiceSpecificError());
- }
- }
-
- if (commandLength == 0) {
+ const auto& commands = mWriter.getPendingCommands();
+ if (commands.empty()) {
mWriter.reset();
return Error::NONE;
}
- AidlExecuteCommandsStatus commandStatus;
- auto status =
- mAidlComposerClient->executeCommands(commandLength, commandHandles, &commandStatus);
- // executeCommands can fail because of out-of-fd and we do not want to
- // abort() in that case
+ std::vector<CommandResultPayload> results;
+ auto status = mAidlComposerClient->executeCommands(commands, &results);
if (!status.isOk()) {
ALOGE("executeCommands failed %s", status.getDescription().c_str());
return static_cast<Error>(status.getServiceSpecificError());
}
- // set up new output command queue if necessary
- if (commandStatus.queueChanged) {
- ::aidl::android::hardware::common::fmq::MQDescriptor<
- int32_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
- outputCommandQueue;
- status = mAidlComposerClient->getOutputCommandQueue(&outputCommandQueue);
- if (!status.isOk()) {
- ALOGE("getOutputCommandQueue failed %s", status.getDescription().c_str());
- return static_cast<Error>(status.getServiceSpecificError());
+ mReader.parse(results);
+ const auto commandErrors = mReader.takeErrors();
+ Error error = Error::NONE;
+ for (const auto& cmdErr : commandErrors) {
+ const auto index = static_cast<size_t>(cmdErr.commandIndex);
+ if (index < 0 || index >= commands.size()) {
+ ALOGE("invalid command index %zu", index);
+ return Error::BAD_PARAMETER;
}
- mReader.setMQDescriptor(outputCommandQueue);
- }
-
- Error error;
- if (mReader.readQueue(commandStatus.length, std::move(commandStatus.handles))) {
- error = static_cast<Error>(mReader.parse());
- mReader.reset();
- } else {
- error = Error::NO_RESOURCES;
- }
-
- if (error == Error::NONE) {
- std::vector<AidlCommandReader::CommandError> commandErrors = mReader.takeErrors();
-
- for (const auto& cmdErr : commandErrors) {
- auto command = mWriter.getCommand(cmdErr.location);
- if (command == Command::VALIDATE_DISPLAY || command == Command::PRESENT_DISPLAY ||
- command == Command::PRESENT_OR_VALIDATE_DISPLAY) {
- error = cmdErr.error;
+ const auto& command = commands[index];
+ if (command.getTag() == command::CommandPayload::Tag::displayCommand) {
+ const auto& displayCommand =
+ command.get<command::CommandPayload::Tag::displayCommand>();
+ if (displayCommand.validateDisplay || displayCommand.presentDisplay ||
+ displayCommand.presentOrValidateDisplay) {
+ error = translate<Error>(cmdErr.errorCode);
} else {
- ALOGW("command 0x%x generated error %d", command, cmdErr.error);
+ ALOGW("command '%s' generated error %" PRId32, command.toString().c_str(),
+ cmdErr.errorCode);
}
}
}
@@ -792,9 +751,8 @@
Error AidlComposer::setLayerPerFrameMetadata(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerPerFrameMetadata(translate<AidlPerFrameMetadata>(perFrameMetadatas));
+ mWriter.setLayerPerFrameMetadata(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlPerFrameMetadata>(perFrameMetadatas));
return Error::NONE;
}
@@ -855,9 +813,7 @@
}
Error AidlComposer::setLayerColorTransform(Display display, Layer layer, const float* matrix) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerColorTransform(matrix);
+ mWriter.setLayerColorTransform(translate<int64_t>(display), translate<int64_t>(layer), matrix);
return Error::NONE;
}
@@ -921,9 +877,8 @@
Error AidlComposer::setLayerPerFrameMetadataBlobs(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerPerFrameMetadataBlobs(translate<AidlPerFrameMetadataBlob>(metadata));
+ mWriter.setLayerPerFrameMetadataBlobs(translate<int64_t>(display), translate<int64_t>(layer),
+ translate<AidlPerFrameMetadataBlob>(metadata));
return Error::NONE;
}
@@ -1032,9 +987,8 @@
V2_4::Error AidlComposer::setLayerGenericMetadata(Display display, Layer layer,
const std::string& key, bool mandatory,
const std::vector<uint8_t>& value) {
- mWriter.selectDisplay(translate<int64_t>(display));
- mWriter.selectLayer(translate<int64_t>(layer));
- mWriter.setLayerGenericMetadata(key, mandatory, value);
+ mWriter.setLayerGenericMetadata(translate<int64_t>(display), translate<int64_t>(layer), key,
+ mandatory, value);
return V2_4::Error::NONE;
}
@@ -1051,320 +1005,18 @@
}
Error AidlComposer::getClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
- mReader.takeClientTargetProperty(display, outClientTargetProperty);
+ Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
+ float* whitePointNits) {
+ ClientTargetProperty property;
+ mReader.takeClientTargetProperty(translate<int64_t>(display), &property, whitePointNits);
+ *outClientTargetProperty = translate<IComposerClient::ClientTargetProperty>(property);
return Error::NONE;
}
-AidlCommandReader::~AidlCommandReader() {
- resetData();
-}
-
-int AidlCommandReader::parse() {
- resetData();
-
- Command command;
- uint16_t length = 0;
-
- while (!isEmpty()) {
- if (!beginCommand(&command, &length)) {
- break;
- }
-
- bool parsed = false;
- switch (command) {
- case Command::SELECT_DISPLAY:
- parsed = parseSelectDisplay(length);
- break;
- case Command::SET_ERROR:
- parsed = parseSetError(length);
- break;
- case Command::SET_CHANGED_COMPOSITION_TYPES:
- parsed = parseSetChangedCompositionTypes(length);
- break;
- case Command::SET_DISPLAY_REQUESTS:
- parsed = parseSetDisplayRequests(length);
- break;
- case Command::SET_PRESENT_FENCE:
- parsed = parseSetPresentFence(length);
- break;
- case Command::SET_RELEASE_FENCES:
- parsed = parseSetReleaseFences(length);
- break;
- case Command ::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT:
- parsed = parseSetPresentOrValidateDisplayResult(length);
- break;
- case Command::SET_CLIENT_TARGET_PROPERTY:
- parsed = parseSetClientTargetProperty(length);
- break;
- default:
- parsed = false;
- break;
- }
-
- endCommand();
-
- if (!parsed) {
- ALOGE("failed to parse command 0x%x length %" PRIu16, command, length);
- break;
- }
- }
-
- return isEmpty() ? 0 : AidlIComposerClient::EX_NO_RESOURCES;
-}
-
-bool AidlCommandReader::parseSelectDisplay(uint16_t length) {
- if (length != CommandWriterBase::kSelectDisplayLength) {
- return false;
- }
-
- mCurrentReturnData = &mReturnData[read64()];
-
- return true;
-}
-
-bool AidlCommandReader::parseSetError(uint16_t length) {
- if (length != CommandWriterBase::kSetErrorLength) {
- return false;
- }
-
- auto location = read();
- auto error = static_cast<Error>(readSigned());
-
- mErrors.emplace_back(CommandError{location, error});
-
- return true;
-}
-
-bool AidlCommandReader::parseSetChangedCompositionTypes(uint16_t length) {
- // (layer id [64bit], composition type [32bit]) pairs
- static constexpr int kCommandWords = 3;
-
- if (length % kCommandWords != 0 || !mCurrentReturnData) {
- return false;
- }
-
- uint32_t count = length / kCommandWords;
- mCurrentReturnData->changedLayers.reserve(count);
- mCurrentReturnData->compositionTypes.reserve(count);
- while (count > 0) {
- auto layer = read64();
- auto type = static_cast<IComposerClient::Composition>(readSigned());
-
- mCurrentReturnData->changedLayers.push_back(layer);
- mCurrentReturnData->compositionTypes.push_back(type);
-
- count--;
- }
-
- return true;
-}
-
-bool AidlCommandReader::parseSetDisplayRequests(uint16_t length) {
- // display requests [32 bit] followed by
- // (layer id [64bit], layer requests [32bit]) pairs
- static constexpr int kDisplayRequestsWords = 1;
- static constexpr int kCommandWords = 3;
- if (length % kCommandWords != kDisplayRequestsWords || !mCurrentReturnData) {
- return false;
- }
-
- mCurrentReturnData->displayRequests = read();
-
- uint32_t count = (length - kDisplayRequestsWords) / kCommandWords;
- mCurrentReturnData->requestedLayers.reserve(count);
- mCurrentReturnData->requestMasks.reserve(count);
- while (count > 0) {
- auto layer = read64();
- auto layerRequestMask = read();
-
- mCurrentReturnData->requestedLayers.push_back(layer);
- mCurrentReturnData->requestMasks.push_back(layerRequestMask);
-
- count--;
- }
-
- return true;
-}
-
-bool AidlCommandReader::parseSetPresentFence(uint16_t length) {
- if (length != CommandWriterBase::kSetPresentFenceLength || !mCurrentReturnData) {
- return false;
- }
-
- if (mCurrentReturnData->presentFence >= 0) {
- close(mCurrentReturnData->presentFence);
- }
- mCurrentReturnData->presentFence = readFence();
-
- return true;
-}
-
-bool AidlCommandReader::parseSetReleaseFences(uint16_t length) {
- // (layer id [64bit], release fence index [32bit]) pairs
- static constexpr int kCommandWords = 3;
-
- if (length % kCommandWords != 0 || !mCurrentReturnData) {
- return false;
- }
-
- uint32_t count = length / kCommandWords;
- mCurrentReturnData->releasedLayers.reserve(count);
- mCurrentReturnData->releaseFences.reserve(count);
- while (count > 0) {
- auto layer = read64();
- auto fence = readFence();
-
- mCurrentReturnData->releasedLayers.push_back(layer);
- mCurrentReturnData->releaseFences.push_back(fence);
-
- count--;
- }
-
- return true;
-}
-
-bool AidlCommandReader::parseSetPresentOrValidateDisplayResult(uint16_t length) {
- if (length != CommandWriterBase::kPresentOrValidateDisplayResultLength || !mCurrentReturnData) {
- return false;
- }
- mCurrentReturnData->presentOrValidateState = read();
- return true;
-}
-
-bool AidlCommandReader::parseSetClientTargetProperty(uint16_t length) {
- if (length != CommandWriterBase::kSetClientTargetPropertyLength || !mCurrentReturnData) {
- return false;
- }
- mCurrentReturnData->clientTargetProperty.pixelFormat = static_cast<PixelFormat>(readSigned());
- mCurrentReturnData->clientTargetProperty.dataspace = static_cast<Dataspace>(readSigned());
- return true;
-}
-
-void AidlCommandReader::resetData() {
- mErrors.clear();
-
- for (auto& data : mReturnData) {
- if (data.second.presentFence >= 0) {
- close(data.second.presentFence);
- }
- for (auto fence : data.second.releaseFences) {
- if (fence >= 0) {
- close(fence);
- }
- }
- }
-
- mReturnData.clear();
- mCurrentReturnData = nullptr;
-}
-
-std::vector<AidlCommandReader::CommandError> AidlCommandReader::takeErrors() {
- return std::move(mErrors);
-}
-
-bool AidlCommandReader::hasChanges(Display display, uint32_t* outNumChangedCompositionTypes,
- uint32_t* outNumLayerRequestMasks) const {
- auto found = mReturnData.find(display);
- if (found == mReturnData.end()) {
- *outNumChangedCompositionTypes = 0;
- *outNumLayerRequestMasks = 0;
- return false;
- }
-
- const ReturnData& data = found->second;
-
- *outNumChangedCompositionTypes = static_cast<uint32_t>(data.compositionTypes.size());
- *outNumLayerRequestMasks = static_cast<uint32_t>(data.requestMasks.size());
-
- return !(data.compositionTypes.empty() && data.requestMasks.empty());
-}
-
-void AidlCommandReader::takeChangedCompositionTypes(
- Display display, std::vector<Layer>* outLayers,
- std::vector<IComposerClient::Composition>* outTypes) {
- auto found = mReturnData.find(display);
- if (found == mReturnData.end()) {
- outLayers->clear();
- outTypes->clear();
- return;
- }
-
- ReturnData& data = found->second;
-
- *outLayers = std::move(data.changedLayers);
- *outTypes = std::move(data.compositionTypes);
-}
-
-void AidlCommandReader::takeDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
- std::vector<Layer>* outLayers,
- std::vector<uint32_t>* outLayerRequestMasks) {
- auto found = mReturnData.find(display);
- if (found == mReturnData.end()) {
- *outDisplayRequestMask = 0;
- outLayers->clear();
- outLayerRequestMasks->clear();
- return;
- }
-
- ReturnData& data = found->second;
-
- *outDisplayRequestMask = data.displayRequests;
- *outLayers = std::move(data.requestedLayers);
- *outLayerRequestMasks = std::move(data.requestMasks);
-}
-
-void AidlCommandReader::takeReleaseFences(Display display, std::vector<Layer>* outLayers,
- std::vector<int>* outReleaseFences) {
- auto found = mReturnData.find(display);
- if (found == mReturnData.end()) {
- outLayers->clear();
- outReleaseFences->clear();
- return;
- }
-
- ReturnData& data = found->second;
-
- *outLayers = std::move(data.releasedLayers);
- *outReleaseFences = std::move(data.releaseFences);
-}
-
-void AidlCommandReader::takePresentFence(Display display, int* outPresentFence) {
- auto found = mReturnData.find(display);
- if (found == mReturnData.end()) {
- *outPresentFence = -1;
- return;
- }
-
- ReturnData& data = found->second;
-
- *outPresentFence = data.presentFence;
- data.presentFence = -1;
-}
-
-void AidlCommandReader::takePresentOrValidateStage(Display display, uint32_t* state) {
- auto found = mReturnData.find(display);
- if (found == mReturnData.end()) {
- *state = static_cast<uint32_t>(-1);
- return;
- }
- ReturnData& data = found->second;
- *state = data.presentOrValidateState;
-}
-
-void AidlCommandReader::takeClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
- auto found = mReturnData.find(display);
-
- // If not found, return the default values.
- if (found == mReturnData.end()) {
- outClientTargetProperty->pixelFormat = PixelFormat::RGBA_8888;
- outClientTargetProperty->dataspace = Dataspace::UNKNOWN;
- return;
- }
-
- ReturnData& data = found->second;
- *outClientTargetProperty = data.clientTargetProperty;
+Error AidlComposer::setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) {
+ mWriter.setLayerWhitePointNits(translate<int64_t>(display), translate<int64_t>(layer),
+ whitePointNits);
+ return Error::NONE;
}
} // namespace Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index a6d9500..8cae25f 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -43,95 +43,10 @@
using AidlCommandWriterBase = aidl::android::hardware::graphics::composer3::CommandWriterBase;
using AidlCommandReaderBase = aidl::android::hardware::graphics::composer3::CommandReaderBase;
+using aidl::android::hardware::graphics::composer3::command::CommandResultPayload;
class AidlIComposerCallbackWrapper;
-class AidlCommandReader : public AidlCommandReaderBase {
-public:
- ~AidlCommandReader();
-
- // Parse and execute commands from the command queue. The commands are
- // actually return values from the server and will be saved in ReturnData.
- int parse();
-
- // Get and clear saved errors.
- struct CommandError {
- uint32_t location;
- Error error;
- };
- std::vector<CommandError> takeErrors();
-
- bool hasChanges(Display display, uint32_t* outNumChangedCompositionTypes,
- uint32_t* outNumLayerRequestMasks) const;
-
- // Get and clear saved changed composition types.
- void takeChangedCompositionTypes(Display display, std::vector<Layer>* outLayers,
- std::vector<IComposerClient::Composition>* outTypes);
-
- // Get and clear saved display requests.
- void takeDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
- std::vector<Layer>* outLayers,
- std::vector<uint32_t>* outLayerRequestMasks);
-
- // Get and clear saved release fences.
- void takeReleaseFences(Display display, std::vector<Layer>* outLayers,
- std::vector<int>* outReleaseFences);
-
- // Get and clear saved present fence.
- void takePresentFence(Display display, int* outPresentFence);
-
- // Get what stage succeeded during PresentOrValidate: Present or Validate
- void takePresentOrValidateStage(Display display, uint32_t* state);
-
- // Get the client target properties requested by hardware composer.
- void takeClientTargetProperty(Display display,
- IComposerClient::ClientTargetProperty* outClientTargetProperty);
-
-private:
- void resetData();
-
- bool parseSelectDisplay(uint16_t length);
- bool parseSetError(uint16_t length);
- bool parseSetChangedCompositionTypes(uint16_t length);
- bool parseSetDisplayRequests(uint16_t length);
- bool parseSetPresentFence(uint16_t length);
- bool parseSetReleaseFences(uint16_t length);
- bool parseSetPresentOrValidateDisplayResult(uint16_t length);
- bool parseSetClientTargetProperty(uint16_t length);
-
- struct ReturnData {
- uint32_t displayRequests = 0;
-
- std::vector<Layer> changedLayers;
- std::vector<IComposerClient::Composition> compositionTypes;
-
- std::vector<Layer> requestedLayers;
- std::vector<uint32_t> requestMasks;
-
- int presentFence = -1;
-
- std::vector<Layer> releasedLayers;
- std::vector<int> releaseFences;
-
- uint32_t presentOrValidateState;
-
- // Composer 2.4 implementation can return a client target property
- // structure to indicate the client target properties that hardware
- // composer requests. The composer client must change the client target
- // properties to match this request.
- IComposerClient::ClientTargetProperty clientTargetProperty{PixelFormat::RGBA_8888,
- Dataspace::UNKNOWN};
- };
-
- std::vector<CommandError> mErrors;
- std::unordered_map<Display, ReturnData> mReturnData;
-
- // When SELECT_DISPLAY is parsed, this is updated to point to the
- // display's return data in mReturnData. We use it to avoid repeated
- // map lookups.
- ReturnData* mCurrentReturnData;
-};
-
// Composer is a wrapper to IComposer, a proxy to server-side composer.
class AidlComposer final : public Hwc2::Composer {
public:
@@ -279,18 +194,12 @@
bool mandatory, const std::vector<uint8_t>& value) override;
V2_4::Error getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
- Error getClientTargetProperty(
- Display display,
- IComposerClient::ClientTargetProperty* outClientTargetProperty) override;
+ Error getClientTargetProperty(Display display,
+ IComposerClient::ClientTargetProperty* outClientTargetProperty,
+ float* outClientTargetWhitePointNits) override;
+ Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override;
private:
- class AidlCommandWriter : public AidlCommandWriterBase {
- public:
- explicit AidlCommandWriter(uint32_t initialMaxSize)
- : AidlCommandWriterBase(initialMaxSize) {}
- ~AidlCommandWriter() override {}
- };
-
// Many public functions above simply write a command into the command
// queue to batch the calls. validateDisplay and presentDisplay will call
// this function to execute the command queue.
@@ -306,8 +215,8 @@
// 1. Tightly coupling this cache to the max size of BufferQueue
// 2. Adding an additional slot for the layer caching feature in SurfaceFlinger (see: Planner.h)
static const constexpr uint32_t kMaxLayerBufferCount = BufferQueue::NUM_BUFFER_SLOTS + 1;
- AidlCommandWriter mWriter;
- AidlCommandReader mReader;
+ AidlCommandWriterBase mWriter;
+ AidlCommandReaderBase mReader;
// Aidl interface
using AidlIComposer = aidl::android::hardware::graphics::composer3::IComposer;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 3bbce7b..3cc5e5e 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -221,7 +221,11 @@
virtual V2_4::Error getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
virtual Error getClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0;
+ Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
+ float* outWhitePointNits) = 0;
+
+ // AIDL Composer
+ virtual Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) = 0;
};
} // namespace android::Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index e21b0da..596666c 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -555,8 +555,10 @@
return static_cast<Error>(intError);
}
-Error Display::getClientTargetProperty(ClientTargetProperty* outClientTargetProperty) {
- const auto error = mComposer.getClientTargetProperty(mId, outClientTargetProperty);
+Error Display::getClientTargetProperty(ClientTargetProperty* outClientTargetProperty,
+ float* outWhitePointNits) {
+ const auto error =
+ mComposer.getClientTargetProperty(mId, outClientTargetProperty, outWhitePointNits);
return static_cast<Error>(error);
}
@@ -919,6 +921,16 @@
return static_cast<Error>(intError);
}
+// AIDL HAL
+Error Layer::setWhitePointNits(float whitePointNits) {
+ if (CC_UNLIKELY(!mDisplay)) {
+ return Error::BAD_DISPLAY;
+ }
+
+ auto intError = mComposer.setLayerWhitePointNits(mDisplay->getId(), mId, whitePointNits);
+ return static_cast<Error>(intError);
+}
+
} // namespace impl
} // namespace HWC2
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index a65efb2..5e0ba06 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -146,7 +146,7 @@
std::vector<hal::ContentType>*) const = 0;
[[clang::warn_unused_result]] virtual hal::Error setContentType(hal::ContentType) = 0;
[[clang::warn_unused_result]] virtual hal::Error getClientTargetProperty(
- hal::ClientTargetProperty* outClientTargetProperty) = 0;
+ hal::ClientTargetProperty* outClientTargetProperty, float* outWhitePointNits) = 0;
};
namespace impl {
@@ -209,7 +209,8 @@
hal::Error getSupportedContentTypes(
std::vector<hal::ContentType>* outSupportedContentTypes) const override;
hal::Error setContentType(hal::ContentType) override;
- hal::Error getClientTargetProperty(hal::ClientTargetProperty* outClientTargetProperty) override;
+ hal::Error getClientTargetProperty(hal::ClientTargetProperty* outClientTargetProperty,
+ float* outWhitePointNits) override;
// Other Display methods
hal::HWDisplayId getId() const override { return mId; }
@@ -288,6 +289,9 @@
// Composer HAL 2.4
[[clang::warn_unused_result]] virtual hal::Error setLayerGenericMetadata(
const std::string& name, bool mandatory, const std::vector<uint8_t>& value) = 0;
+
+ // AIDL HAL
+ [[clang::warn_unused_result]] virtual hal::Error setWhitePointNits(float whitePointNits) = 0;
};
namespace impl {
@@ -331,6 +335,9 @@
hal::Error setLayerGenericMetadata(const std::string& name, bool mandatory,
const std::vector<uint8_t>& value) override;
+ // AIDL HAL
+ hal::Error setWhitePointNits(float whitePointNits) override;
+
private:
// These are references to data owned by HWC2::Device, which will outlive
// this HWC2::Layer, so these references are guaranteed to be valid for
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 06f5df5..d851e22 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -522,11 +522,13 @@
RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
DeviceRequestedChanges::ClientTargetProperty clientTargetProperty;
- error = hwcDisplay->getClientTargetProperty(&clientTargetProperty);
+ float clientTargetWhitePointNits;
+ error = hwcDisplay->getClientTargetProperty(&clientTargetProperty, &clientTargetWhitePointNits);
outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
std::move(layerRequests),
- std::move(clientTargetProperty)});
+ std::move(clientTargetProperty),
+ clientTargetWhitePointNits});
error = hwcDisplay->acceptChanges();
RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 0a090da..bd79977 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -79,6 +79,7 @@
DisplayRequests displayRequests;
LayerRequests layerRequests;
ClientTargetProperty clientTargetProperty;
+ float clientTargetWhitePointNits;
};
struct HWCDisplayMode {
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 6c40598..11d41c0 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -1164,8 +1164,14 @@
}
Error HidlComposer::getClientTargetProperty(
- Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty) {
+ Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
+ float* outWhitePointNits) {
mReader.takeClientTargetProperty(display, outClientTargetProperty);
+ *outWhitePointNits = -1.f;
+ return Error::NONE;
+}
+
+Error HidlComposer::setLayerWhitePointNits(Display, Layer, float) {
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index ad253a2..18c0635 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -304,9 +304,10 @@
bool mandatory, const std::vector<uint8_t>& value) override;
V2_4::Error getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
- Error getClientTargetProperty(
- Display display,
- IComposerClient::ClientTargetProperty* outClientTargetProperty) override;
+ Error getClientTargetProperty(Display display,
+ IComposerClient::ClientTargetProperty* outClientTargetProperty,
+ float* outWhitePointNits) override;
+ Error setLayerWhitePointNits(Display display, Layer layer, float whitePointNits) override;
private:
class CommandWriter : public CommandWriterBase {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index dfb99cc..b395159 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -46,6 +46,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
+#include <ui/DataspaceUtils.h>
#include <ui/DebugUtils.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
@@ -418,6 +419,8 @@
compositionState->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
compositionState->alpha = alpha;
+ compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
+ compositionState->blurRegions = drawingState.blurRegions;
compositionState->stretchEffect = getStretchEffect();
}
@@ -482,6 +485,11 @@
// If there are no visible region changes, we still need to update blur parameters.
compositionState->blurRegions = drawingState.blurRegions;
compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
+
+ // Layer framerate is used in caching decisions.
+ // Retrieve it from the scheduler which maintains an instance of LayerHistory, and store it in
+ // LayerFECompositionState where it would be visible to Flattener.
+ compositionState->fps = mFlinger->getLayerFramerate(systemTime(), getSequence());
}
void Layer::prepareCursorCompositionState() {
@@ -578,6 +586,8 @@
layerSettings.alpha = alpha;
layerSettings.sourceDataspace = getDataSpace();
+
+ layerSettings.whitePointNits = targetSettings.whitePointNits;
switch (targetSettings.blurSetting) {
case LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled:
layerSettings.backgroundBlurRadius = getBackgroundBlurRadius();
@@ -932,7 +942,6 @@
setTransactionFlags(eTransactionNeeded);
return true;
}
-
bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix,
bool allowNonRectPreservingTransforms) {
ui::Transform t;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 84e3548..74a2ca7 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -84,42 +84,38 @@
void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) {
std::lock_guard lock(mLock);
- for (const auto& info : mLayerInfos) {
- LOG_ALWAYS_FATAL_IF(info.first == layer, "%s already registered", layer->getName().c_str());
- }
+ LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first !=
+ LayerHistory::layerStatus::NotFound,
+ "%s already registered", layer->getName().c_str());
auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type);
- mLayerInfos.emplace_back(layer, std::move(info));
+
+ // The layer can be placed on either map, it is assumed that partitionLayers() will be called
+ // to correct them.
+ mInactiveLayerInfos.insert({layer->getSequence(), std::make_pair(layer, std::move(info))});
}
void LayerHistory::deregisterLayer(Layer* layer) {
std::lock_guard lock(mLock);
-
- const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
- [layer](const auto& pair) { return pair.first == layer; });
- LOG_ALWAYS_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
-
- const size_t i = static_cast<size_t>(it - mLayerInfos.begin());
- if (i < mActiveLayersEnd) {
- mActiveLayersEnd--;
+ if (!mActiveLayerInfos.erase(layer->getSequence())) {
+ if (!mInactiveLayerInfos.erase(layer->getSequence())) {
+ LOG_ALWAYS_FATAL("%s: unknown layer %p", __FUNCTION__, layer);
+ }
}
- const size_t last = mLayerInfos.size() - 1;
- std::swap(mLayerInfos[i], mLayerInfos[last]);
- mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(last));
}
void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
LayerUpdateType updateType) {
std::lock_guard lock(mLock);
+ auto id = layer->getSequence();
- const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
- [layer](const auto& pair) { return pair.first == layer; });
- if (it == mLayerInfos.end()) {
+ auto [found, layerPair] = findLayer(id);
+ if (found == LayerHistory::layerStatus::NotFound) {
// Offscreen layer
ALOGV("LayerHistory::record: %s not registered", layer->getName().c_str());
return;
}
- const auto& info = it->second;
+ const auto& info = layerPair->second;
const auto layerProps = LayerInfo::LayerProps{
.visible = layer->isVisible(),
.bounds = layer->getBounds(),
@@ -131,9 +127,10 @@
info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps);
// Activate layer if inactive.
- if (const auto end = activeLayers().end(); it >= end) {
- std::iter_swap(it, end);
- mActiveLayersEnd++;
+ if (found == LayerHistory::layerStatus::LayerInInactiveMap) {
+ mActiveLayerInfos.insert(
+ {id, std::make_pair(layerPair->first, std::move(layerPair->second))});
+ mInactiveLayerInfos.erase(id);
}
}
@@ -145,7 +142,8 @@
partitionLayers(now);
- for (const auto& [layer, info] : activeLayers()) {
+ for (const auto& [key, value] : mActiveLayerInfos) {
+ auto& info = value.second;
const auto frameRateSelectionPriority = info->getFrameRateSelectionPriority();
const auto layerFocused = Layer::isLayerFocusedBasedOnPriority(frameRateSelectionPriority);
ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority,
@@ -179,12 +177,29 @@
void LayerHistory::partitionLayers(nsecs_t now) {
const nsecs_t threshold = getActiveLayerThreshold(now);
- // Collect expired and inactive layers after active layers.
- size_t i = 0;
- while (i < mActiveLayersEnd) {
- auto& [layerUnsafe, info] = mLayerInfos[i];
+ // iterate over inactive map
+ LayerInfos::iterator it = mInactiveLayerInfos.begin();
+ while (it != mInactiveLayerInfos.end()) {
+ auto& [layerUnsafe, info] = it->second;
if (isLayerActive(*info, threshold)) {
- i++;
+ // move this to the active map
+
+ mActiveLayerInfos.insert({it->first, std::move(it->second)});
+ it = mInactiveLayerInfos.erase(it);
+ } else {
+ if (CC_UNLIKELY(mTraceEnabled)) {
+ trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
+ }
+ info->onLayerInactive(now);
+ it++;
+ }
+ }
+
+ // iterate over active map
+ it = mActiveLayerInfos.begin();
+ while (it != mActiveLayerInfos.end()) {
+ auto& [layerUnsafe, info] = it->second;
+ if (isLayerActive(*info, threshold)) {
// Set layer vote if set
const auto frameRate = info->getSetFrameRateVote();
const auto voteType = [&]() {
@@ -206,30 +221,68 @@
} else {
info->resetLayerVote();
}
- continue;
- }
- if (CC_UNLIKELY(mTraceEnabled)) {
- trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
+ it++;
+ } else {
+ if (CC_UNLIKELY(mTraceEnabled)) {
+ trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
+ }
+ info->onLayerInactive(now);
+ // move this to the inactive map
+ mInactiveLayerInfos.insert({it->first, std::move(it->second)});
+ it = mActiveLayerInfos.erase(it);
}
-
- info->onLayerInactive(now);
- std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]);
}
}
void LayerHistory::clear() {
std::lock_guard lock(mLock);
-
- for (const auto& [layer, info] : activeLayers()) {
- info->clearHistory(systemTime());
+ for (const auto& [key, value] : mActiveLayerInfos) {
+ value.second->clearHistory(systemTime());
}
}
std::string LayerHistory::dump() const {
std::lock_guard lock(mLock);
- return base::StringPrintf("LayerHistory{size=%zu, active=%zu}", mLayerInfos.size(),
- mActiveLayersEnd);
+ return base::StringPrintf("LayerHistory{size=%zu, active=%zu}",
+ mActiveLayerInfos.size() + mInactiveLayerInfos.size(),
+ mActiveLayerInfos.size());
+}
+
+float LayerHistory::getLayerFramerate(nsecs_t now, int32_t id) const {
+ std::lock_guard lock(mLock);
+ auto [found, layerPair] = findLayer(id);
+ if (found != LayerHistory::layerStatus::NotFound) {
+ return layerPair->second->getFps(now).getValue();
+ }
+ return 0.f;
+}
+
+std::pair<LayerHistory::layerStatus, LayerHistory::LayerPair*> LayerHistory::findLayer(int32_t id) {
+ // the layer could be in either the active or inactive map, try both
+ auto it = mActiveLayerInfos.find(id);
+ if (it != mActiveLayerInfos.end()) {
+ return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second));
+ }
+ it = mInactiveLayerInfos.find(id);
+ if (it != mInactiveLayerInfos.end()) {
+ return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second));
+ }
+ return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr);
+}
+
+std::pair<LayerHistory::layerStatus, const LayerHistory::LayerPair*> LayerHistory::findLayer(
+ int32_t id) const {
+ // the layer could be in either the active or inactive map, try both
+ auto it = mActiveLayerInfos.find(id);
+ if (it != mActiveLayerInfos.end()) {
+ return std::make_pair(LayerHistory::layerStatus::LayerInActiveMap, &(it->second));
+ }
+ it = mInactiveLayerInfos.find(id);
+ if (it != mInactiveLayerInfos.end()) {
+ return std::make_pair(LayerHistory::layerStatus::LayerInInactiveMap, &(it->second));
+ }
+ return std::make_pair(LayerHistory::layerStatus::NotFound, nullptr);
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 8d56951..cc55700 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -20,6 +20,7 @@
#include <utils/RefBase.h>
#include <utils/Timers.h>
+#include <map>
#include <memory>
#include <mutex>
#include <string>
@@ -72,34 +73,43 @@
void deregisterLayer(Layer*);
std::string dump() const;
+ // return the frames per second of the layer with the given sequence id.
+ float getLayerFramerate(nsecs_t now, int32_t id) const;
+
private:
friend class LayerHistoryTest;
friend class TestableScheduler;
using LayerPair = std::pair<Layer*, std::unique_ptr<LayerInfo>>;
- using LayerInfos = std::vector<LayerPair>;
+ // keyed by id as returned from Layer::getSequence()
+ using LayerInfos = std::unordered_map<int32_t, LayerPair>;
- struct ActiveLayers {
- LayerInfos& infos;
- const size_t index;
+ // Iterates over layers maps moving all active layers to mActiveLayerInfos and all inactive
+ // layers to mInactiveLayerInfos.
+ // worst case time complexity is O(2 * inactive + active)
+ void partitionLayers(nsecs_t now) REQUIRES(mLock);
- auto begin() { return infos.begin(); }
- auto end() { return begin() + static_cast<long>(index); }
+ enum class layerStatus {
+ NotFound,
+ LayerInActiveMap,
+ LayerInInactiveMap,
};
- ActiveLayers activeLayers() REQUIRES(mLock) { return {mLayerInfos, mActiveLayersEnd}; }
-
- // Iterates over layers in a single pass, swapping pairs such that active layers precede
- // inactive layers, and inactive layers precede expired layers. Removes expired layers by
- // truncating after inactive layers.
- void partitionLayers(nsecs_t now) REQUIRES(mLock);
+ // looks up a layer by sequence id in both layerInfo maps.
+ // The first element indicates if and where the item was found
+ std::pair<layerStatus, LayerHistory::LayerPair*> findLayer(int32_t id) REQUIRES(mLock);
+ std::pair<layerStatus, const LayerHistory::LayerPair*> findLayer(int32_t id) const
+ REQUIRES(mLock);
mutable std::mutex mLock;
- // Partitioned such that active layers precede inactive layers. For fast lookup, the few active
- // layers are at the front, and weak pointers are stored in contiguous memory to hit the cache.
- LayerInfos mLayerInfos GUARDED_BY(mLock);
- size_t mActiveLayersEnd GUARDED_BY(mLock) = 0;
+ // Partitioned into two maps to facility two kinds of retrieval:
+ // 1. retrieval of a layer by id (attempt lookup in both maps)
+ // 2. retrieval of all active layers (iterate that map)
+ // The partitioning is allowed to become out of date but calling partitionLayers refreshes the
+ // validity of each map.
+ LayerInfos mActiveLayerInfos GUARDED_BY(mLock);
+ LayerInfos mInactiveLayerInfos GUARDED_BY(mLock);
uint32_t mDisplayArea = 0;
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index ae61eeb..943615c 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -75,12 +75,16 @@
}
bool LayerInfo::isFrequent(nsecs_t now) const {
+ using fps_approx_ops::operator>=;
// If we know nothing about this layer we consider it as frequent as it might be the start
// of an animation.
if (mFrameTimes.size() < kFrequentLayerWindowSize) {
return true;
}
+ return getFps(now) >= kMinFpsForFrequentLayer;
+}
+Fps LayerInfo::getFps(nsecs_t now) const {
// Find the first active frame
auto it = mFrameTimes.begin();
for (; it != mFrameTimes.end(); ++it) {
@@ -91,14 +95,12 @@
const auto numFrames = std::distance(it, mFrameTimes.end());
if (numFrames < kFrequentLayerWindowSize) {
- return false;
+ return Fps();
}
- using fps_approx_ops::operator>=;
-
// Layer is considered frequent if the average frame rate is higher than the threshold
const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
- return Fps::fromPeriodNsecs(totalTime / (numFrames - 1)) >= kMinFpsForFrequentLayer;
+ return Fps::fromPeriodNsecs(totalTime / (numFrames - 1));
}
bool LayerInfo::isAnimating(nsecs_t now) const {
@@ -236,7 +238,7 @@
if (!isFrequent(now)) {
ALOGV("%s is infrequent", mName.c_str());
mLastRefreshRate.animatingOrInfrequent = true;
- // Infrequent layers vote for minimal refresh rate for
+ // Infrequent layers vote for mininal refresh rate for
// battery saving purposes and also to prevent b/135718869.
return {LayerHistory::LayerVoteType::Min, Fps()};
}
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 690abda..2d88a4f 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -178,6 +178,9 @@
// Returns a C string for tracing a vote
const char* getTraceTag(LayerHistory::LayerVoteType type) const;
+ // Return the framerate of this layer.
+ Fps getFps(nsecs_t now) const;
+
void onLayerInactive(nsecs_t now) {
// Mark mFrameTimeValidSince to now to ignore all previous frame times.
// We are not deleting the old frame to keep track of whether we should treat the first
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index e127ff7..818f1ed 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -233,6 +233,11 @@
return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
}
+ // Returns the framerate of the layer with the given sequence ID
+ float getLayerFramerate(nsecs_t now, int32_t id) const {
+ return mLayerHistory.getLayerFramerate(now, id);
+ }
+
private:
friend class TestableScheduler;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5f5f1f6..4f38588 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -67,6 +67,7 @@
#include <renderengine/RenderEngine.h>
#include <sys/types.h>
#include <ui/ColorSpace.h>
+#include <ui/DataspaceUtils.h>
#include <ui/DebugUtils.h>
#include <ui/DisplayId.h>
#include <ui/DisplayMode.h>
@@ -93,6 +94,7 @@
#include <type_traits>
#include <unordered_map>
+#include "BackgroundExecutor.h"
#include "BufferLayer.h"
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
@@ -492,7 +494,8 @@
enableLatchUnsignaledConfig = getLatchUnsignaledConfig();
- mTransactionTracingEnabled = property_get_bool("debug.sf.enable_transaction_tracing", false);
+ mTransactionTracingEnabled =
+ !mIsUserBuild && property_get_bool("debug.sf.enable_transaction_tracing", true);
if (mTransactionTracingEnabled) {
mTransactionTracing.enable();
}
@@ -2315,12 +2318,7 @@
mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
const auto layerFe = layer->getCompositionEngineLayerFE();
if (layer->isVisible() && compositionDisplay->includesLayer(layerFe)) {
- const Dataspace transfer =
- static_cast<Dataspace>(layer->getDataSpace() & Dataspace::TRANSFER_MASK);
- const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 ||
- transfer == Dataspace::TRANSFER_HLG);
-
- if (isHdr) {
+ if (isHdrDataspace(layer->getDataSpace())) {
const auto* outputLayer =
compositionDisplay->getOutputLayerForLayer(layerFe);
if (outputLayer) {
@@ -3054,28 +3052,45 @@
return;
}
+ std::vector<WindowInfo> windowInfos;
+ std::vector<DisplayInfo> displayInfos;
+ bool updateWindowInfo = false;
if (mVisibleRegionsDirty || mInputInfoChanged) {
mInputInfoChanged = false;
- notifyWindowInfos();
- } else if (mInputWindowCommands.syncInputWindows) {
- // If the caller requested to sync input windows, but there are no
- // changes to input windows, notify immediately.
- windowInfosReported();
+ updateWindowInfo = true;
+ buildWindowInfos(windowInfos, displayInfos);
}
+ if (!updateWindowInfo && mInputWindowCommands.empty()) {
+ return;
+ }
+ BackgroundExecutor::getInstance().execute([updateWindowInfo,
+ windowInfos = std::move(windowInfos),
+ displayInfos = std::move(displayInfos),
+ inputWindowCommands =
+ std::move(mInputWindowCommands),
+ inputFlinger = mInputFlinger, this]() {
+ ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
+ if (updateWindowInfo) {
+ mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
+ inputWindowCommands.syncInputWindows);
+ } else if (inputWindowCommands.syncInputWindows) {
+ // If the caller requested to sync input windows, but there are no
+ // changes to input windows, notify immediately.
+ windowInfosReported();
+ }
+ for (const auto& focusRequest : inputWindowCommands.focusRequests) {
+ inputFlinger->setFocusedWindow(focusRequest);
+ }
+ });
- for (const auto& focusRequest : mInputWindowCommands.focusRequests) {
- mInputFlinger->setFocusedWindow(focusRequest);
- }
mInputWindowCommands.clear();
}
-void SurfaceFlinger::notifyWindowInfos() {
- std::vector<WindowInfo> windowInfos;
- std::vector<DisplayInfo> displayInfos;
+void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos,
+ std::vector<DisplayInfo>& outDisplayInfos) {
std::unordered_map<uint32_t /*layerStackId*/,
std::pair<bool /* isSecure */, const ui::Transform>>
inputDisplayDetails;
-
for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
if (!display->receivesInput()) {
continue;
@@ -3089,7 +3104,7 @@
layerStackId);
continue;
}
- displayInfos.emplace_back(info);
+ outDisplayInfos.emplace_back(info);
}
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
@@ -3104,15 +3119,10 @@
const auto& [secure, transform] = it->second;
isSecure = secure;
displayTransform = transform;
- } else {
- ALOGE("No input-enabled display found for layer `%s` on layer stack id: %d",
- layer->getDebugName(), layerStackId);
}
- windowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure));
+ outWindowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure));
});
- mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
- mInputWindowCommands.syncInputWindows);
}
void SurfaceFlinger::updateCursorAsync() {
@@ -4328,8 +4338,9 @@
return hasChanges ? eTraversalNeeded : 0;
}
-status_t SurfaceFlinger::mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
- sp<IBinder>* outHandle, int32_t* outLayerId) {
+status_t SurfaceFlinger::mirrorLayer(const LayerCreationArgs& args,
+ const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,
+ int32_t* outLayerId) {
if (!mirrorFromHandle) {
return NAME_NOT_FOUND;
}
@@ -4342,7 +4353,6 @@
if (!mirrorFrom) {
return NAME_NOT_FOUND;
}
- LayerCreationArgs args(this, client, "MirrorRoot", 0, LayerMetadata());
status_t result = createContainerLayer(args, outHandle, &mirrorLayer);
if (result != NO_ERROR) {
return result;
@@ -4352,7 +4362,11 @@
}
*outLayerId = mirrorLayer->sequence;
- return addClientLayer(client, *outHandle, mirrorLayer /* layer */, nullptr /* parent */,
+ if (mTransactionTracingEnabled) {
+ mTransactionTracing.onMirrorLayerAdded((*outHandle)->localBinder(), mirrorLayer->sequence,
+ args.name, mirrorFrom->sequence);
+ }
+ return addClientLayer(args.client, *outHandle, mirrorLayer /* layer */, nullptr /* parent */,
false /* addAsRoot */, nullptr /* outTransformHint */);
}
@@ -4402,10 +4416,6 @@
if (parentLayer != nullptr) {
addToRoot = false;
}
- result = addClientLayer(args.client, *outHandle, layer, parent, addToRoot, outTransformHint);
- if (result != NO_ERROR) {
- return result;
- }
int parentId = -1;
// We can safely promote the layer in binder thread because we have a strong reference
@@ -4414,8 +4424,15 @@
if (parentSp != nullptr) {
parentId = parentSp->getSequence();
}
- mTransactionTracing.onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name,
- args.flags, parentId);
+ if (mTransactionTracingEnabled) {
+ mTransactionTracing.onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name,
+ args.flags, parentId);
+ }
+
+ result = addClientLayer(args.client, *outHandle, layer, parent, addToRoot, outTransformHint);
+ if (result != NO_ERROR) {
+ return result;
+ }
setTransactionFlags(eTransactionNeeded);
*outLayerId = layer->sequence;
@@ -4466,14 +4483,14 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::createEffectLayer(LayerCreationArgs& args, sp<IBinder>* handle,
+status_t SurfaceFlinger::createEffectLayer(const LayerCreationArgs& args, sp<IBinder>* handle,
sp<Layer>* outLayer) {
*outLayer = getFactory().createEffectLayer(args);
*handle = (*outLayer)->getHandle();
return NO_ERROR;
}
-status_t SurfaceFlinger::createContainerLayer(LayerCreationArgs& args, sp<IBinder>* handle,
+status_t SurfaceFlinger::createContainerLayer(const LayerCreationArgs& args, sp<IBinder>* handle,
sp<Layer>* outLayer) {
*outLayer = getFactory().createContainerLayer(args);
*handle = (*outLayer)->getHandle();
@@ -4499,6 +4516,9 @@
markLayerPendingRemovalLocked(layer);
mBufferCountTracker.remove(handle);
layer.clear();
+ if (mTransactionTracingEnabled) {
+ mTransactionTracing.onHandleRemoved(handle);
+ }
}
// ---------------------------------------------------------------------------
@@ -6409,6 +6429,8 @@
BlurSetting::Disabled
: compositionengine::LayerFE::ClientCompositionTargetSettings::
BlurSetting::Enabled,
+ DisplayDevice::sDefaultMaxLumiance,
+
};
std::vector<compositionengine::LayerFE::LayerSettings> results =
layer->prepareClientCompositionList(targetSettings);
@@ -6653,7 +6675,9 @@
if (!layer->isRemovedFromCurrentState()) {
mScheduler->deregisterLayer(layer);
}
- mTransactionTracing.onLayerRemoved(layer->getSequence());
+ if (mTransactionTracingEnabled) {
+ mTransactionTracing.onLayerRemoved(layer->getSequence());
+ }
}
void SurfaceFlinger::onLayerUpdate() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9794639..e1b52c5 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -690,7 +690,8 @@
void updateLayerGeometry();
void updateInputFlinger();
- void notifyWindowInfos();
+ void buildWindowInfos(std::vector<gui::WindowInfo>& outWindowInfos,
+ std::vector<gui::DisplayInfo>& outDisplayInfos);
void commitInputWindowCommands() REQUIRES(mStateLock);
void updateCursorAsync();
@@ -769,13 +770,13 @@
status_t createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
sp<Layer>* outLayer);
- status_t createEffectLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
+ status_t createEffectLayer(const LayerCreationArgs& args, sp<IBinder>* outHandle,
sp<Layer>* outLayer);
- status_t createContainerLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
+ status_t createContainerLayer(const LayerCreationArgs& args, sp<IBinder>* outHandle,
sp<Layer>* outLayer);
- status_t mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
+ status_t mirrorLayer(const LayerCreationArgs& args, const sp<IBinder>& mirrorFromHandle,
sp<IBinder>* outHandle, int32_t* outLayerId);
// called when all clients have released all their references to
@@ -1294,8 +1295,8 @@
const float mInternalDisplayDensity;
const float mEmulatedDisplayDensity;
- sp<os::IInputFlinger> mInputFlinger;
// Should only be accessed by the main thread.
+ sp<os::IInputFlinger> mInputFlinger;
InputWindowCommands mInputWindowCommands;
Hwc2::impl::PowerAdvisor mPowerAdvisor;
@@ -1351,6 +1352,11 @@
const sp<WindowInfosListenerInvoker> mWindowInfosListenerInvoker;
std::unique_ptr<FlagManager> mFlagManager;
+
+ // returns the framerate of the layer with the given sequence ID
+ float getLayerFramerate(nsecs_t now, int32_t id) const {
+ return mScheduler->getLayerFramerate(now, id);
+ }
};
} // namespace android
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 7e12313..378deb0 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -43,7 +43,7 @@
}
proto::TransactionState TransactionProtoParser::toProto(
- const std::unordered_map<int32_t /* layerId */, TracingLayerState> states) {
+ const std::map<int32_t /* layerId */, TracingLayerState>& states) {
proto::TransactionState proto;
for (auto& [layerId, state] : states) {
proto::LayerState layerProto = toProto(state, nullptr);
@@ -278,6 +278,7 @@
proto.set_name(args.name);
proto.set_flags(args.flags);
proto.set_parent_id(args.parentId);
+ proto.set_mirror_from_id(args.mirrorFromId);
return proto;
}
@@ -312,6 +313,7 @@
outArgs.name = proto.name();
outArgs.flags = proto.flags();
outArgs.parentId = proto.parent_id();
+ outArgs.mirrorFromId = proto.mirror_from_id();
}
void TransactionProtoParser::fromProto(const proto::LayerState& proto,
@@ -320,6 +322,7 @@
fromProto(proto, getLayerHandle, static_cast<layer_state_t&>(outState));
if (proto.what() & layer_state_t::eReparent) {
outState.parentId = proto.parent_id();
+ outState.args.parentId = outState.parentId;
}
if (proto.what() & layer_state_t::eRelativeLayerChanged) {
outState.relativeParentId = proto.relative_parent_id();
@@ -508,7 +511,9 @@
DisplayIdToHandleFn getDisplayHandle) {
DisplayState display;
display.what = proto.what();
- display.token = getDisplayHandle(proto.id());
+ if (getDisplayHandle != nullptr) {
+ display.token = getDisplayHandle(proto.id());
+ }
if (display.what & DisplayState::eLayerStackChanged) {
display.layerStack.id = proto.layer_stack();
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index 619ee05..b78d3d9 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -25,8 +25,9 @@
struct TracingLayerCreationArgs {
int32_t layerId;
std::string name;
- uint32_t flags;
- int32_t parentId;
+ uint32_t flags = 0;
+ int32_t parentId = -1;
+ int32_t mirrorFromId = -1;
};
struct TracingLayerState : layer_state_t {
@@ -37,8 +38,7 @@
int32_t parentId;
int32_t relativeParentId;
int32_t inputCropId;
- std::string name;
- uint32_t layerCreationFlags;
+ TracingLayerCreationArgs args;
};
class TransactionProtoParser {
@@ -51,7 +51,7 @@
static proto::TransactionState toProto(const TransactionState&, LayerHandleToIdFn getLayerIdFn,
DisplayHandleToIdFn getDisplayIdFn);
static proto::TransactionState toProto(
- const std::unordered_map<int32_t /* layerId */, TracingLayerState>);
+ const std::map<int32_t /* layerId */, TracingLayerState>&);
static proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args);
@@ -70,4 +70,4 @@
static DisplayState fromProto(const proto::DisplayState&, DisplayIdToHandleFn getDisplayHandle);
};
-} // namespace android::surfaceflinger
\ No newline at end of file
+} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index cf488c2..c1b3d2e 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -199,7 +199,7 @@
entryProto.mutable_transactions()->Add(std::move(it->second));
mQueuedTransactions.erase(it);
} else {
- ALOGE("Could not find transaction id %" PRIu64, id);
+ ALOGW("Could not find transaction id %" PRIu64, id);
}
}
std::vector<proto::TransactionTraceEntry> entries = mBuffer->emplace(std::move(entryProto));
@@ -227,7 +227,23 @@
void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name,
uint32_t flags, int parentId) {
std::scoped_lock lock(mTraceLock);
- TracingLayerCreationArgs args{layerId, name, flags, parentId};
+ TracingLayerCreationArgs args{layerId, name, flags, parentId, -1 /* mirrorFromId */};
+ if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) {
+ ALOGW("Duplicate handles found. %p", layerHandle);
+ }
+ mLayerHandles[layerHandle] = layerId;
+ proto::LayerCreationArgs protoArgs = TransactionProtoParser::toProto(args);
+ proto::LayerCreationArgs protoArgsCopy = protoArgs;
+ mCreatedLayers.push_back(protoArgs);
+}
+
+void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId,
+ const std::string& name, int mirrorFromId) {
+ std::scoped_lock lock(mTraceLock);
+ TracingLayerCreationArgs args{layerId, name, 0 /* flags */, -1 /* parentId */, mirrorFromId};
+ if (mLayerHandles.find(layerHandle) != mLayerHandles.end()) {
+ ALOGW("Duplicate handles found. %p", layerHandle);
+ }
mLayerHandles[layerHandle] = layerId;
mCreatedLayers.emplace_back(TransactionProtoParser::toProto(args));
}
@@ -237,6 +253,11 @@
tryPushToTracingThread();
}
+void TransactionTracing::onHandleRemoved(BBinder* layerHandle) {
+ std::scoped_lock lock(mTraceLock);
+ mLayerHandles.erase(layerHandle);
+}
+
void TransactionTracing::tryPushToTracingThread() {
// Try to acquire the lock from main thread.
if (mMainThreadLock.try_lock()) {
@@ -260,7 +281,11 @@
return -1;
}
auto it = mLayerHandles.find(layerHandle->localBinder());
- return it == mLayerHandles.end() ? -1 : it->second;
+ if (it == mLayerHandles.end()) {
+ ALOGW("Could not find layer handle %p", layerHandle->localBinder());
+ return -1;
+ }
+ return it->second;
}
void TransactionTracing::updateStartingStateLocked(
@@ -270,9 +295,7 @@
for (const proto::LayerCreationArgs& addedLayer : removedEntry.added_layers()) {
TracingLayerState& startingState = mStartingStates[addedLayer.layer_id()];
startingState.layerId = addedLayer.layer_id();
- startingState.name = addedLayer.name();
- startingState.layerCreationFlags = addedLayer.flags();
- startingState.parentId = addedLayer.parent_id();
+ TransactionProtoParser::fromProto(addedLayer, startingState.args);
}
// Merge layer states to starting transaction state.
@@ -280,7 +303,7 @@
for (const proto::LayerState& layerState : transaction.layer_changes()) {
auto it = mStartingStates.find(layerState.layer_id());
if (it == mStartingStates.end()) {
- ALOGE("Could not find layer id %d", layerState.layer_id());
+ ALOGW("Could not find layer id %d", layerState.layer_id());
continue;
}
TransactionProtoParser::fromProto(layerState, nullptr, it->second);
@@ -290,13 +313,6 @@
// Clean up stale starting states since the layer has been removed and the buffer does not
// contain any references to the layer.
for (const int32_t removedLayerId : removedEntry.removed_layers()) {
- auto it = std::find_if(mLayerHandles.begin(), mLayerHandles.end(),
- [removedLayerId](auto& layer) {
- return layer.second == removedLayerId;
- });
- if (it != mLayerHandles.end()) {
- mLayerHandles.erase(it);
- }
mStartingStates.erase(removedLayerId);
}
}
@@ -305,11 +321,13 @@
proto::TransactionTraceEntry* entryProto = proto.add_entry();
entryProto->set_elapsed_realtime_nanos(mStartingTimestamp);
entryProto->set_vsync_id(0);
+ if (mStartingStates.size() == 0) {
+ return;
+ }
+
entryProto->mutable_added_layers()->Reserve(static_cast<int32_t>(mStartingStates.size()));
for (auto& [layerId, state] : mStartingStates) {
- TracingLayerCreationArgs args{layerId, state.name, state.layerCreationFlags,
- state.parentId};
- entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(args));
+ entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(state.args));
}
proto::TransactionState transactionProto = TransactionProtoParser::toProto(mStartingStates);
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
index 0aa22ed..26a3758 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.h
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -64,7 +64,10 @@
void setBufferSize(size_t bufferSizeInBytes);
void onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, uint32_t flags,
int parentId);
+ void onMirrorLayerAdded(BBinder* layerHandle, int layerId, const std::string& name,
+ int mirrorFromId);
void onLayerRemoved(int layerId);
+ void onHandleRemoved(BBinder* layerHandle);
void dump(std::string&) const;
static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024;
static constexpr auto ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024;
@@ -85,8 +88,7 @@
std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock);
std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles
GUARDED_BY(mTraceLock);
- std::unordered_map<int32_t /* layerId */, TracingLayerState> mStartingStates
- GUARDED_BY(mTraceLock);
+ std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock);
// We do not want main thread to block so main thread will try to acquire mMainThreadLock,
// otherwise will push data to temporary container.
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index 10222cc..e31b502 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -53,6 +53,7 @@
string name = 2;
uint32 flags = 3;
int32 parent_id = 4;
+ int32 mirror_from_id = 5;
}
message TransactionState {
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index 575e70d..39d7bd9 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -3,7 +3,7 @@
user system
group graphics drmrpc readproc
capabilities SYS_NICE
- onrestart restart zygote
+ onrestart restart --only-if-running zygote
task_profiles HighPerformance
socket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
socket pdx/system/vr/display/manager stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 561d9e2..5568418 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -119,6 +119,7 @@
static_libs: [
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
+ "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 00687ad..cdb2240 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -63,33 +63,42 @@
const LayerHistory& history() const { return mScheduler->mutableLayerHistory(); }
LayerHistory::Summary summarizeLayerHistory(nsecs_t now) {
- return history().summarize(*mScheduler->refreshRateConfigs(), now);
+ // LayerHistory::summarize makes no guarantee of the order of the elements in the summary
+ // however, for testing only, a stable order is required, therefore we sort the list here.
+ // Any tests requiring ordered results must create layers with names.
+ auto summary = history().summarize(*mScheduler->refreshRateConfigs(), now);
+ std::sort(summary.begin(), summary.end(),
+ [](const RefreshRateConfigs::LayerRequirement& a,
+ const RefreshRateConfigs::LayerRequirement& b) -> bool {
+ return a.name < b.name;
+ });
+ return summary;
}
size_t layerCount() const { return mScheduler->layerHistorySize(); }
- size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; }
+ size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS {
+ return history().mActiveLayerInfos.size();
+ }
auto frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
- const auto& infos = history().mLayerInfos;
- return std::count_if(infos.begin(),
- infos.begin() + static_cast<long>(history().mActiveLayersEnd),
- [now](const auto& pair) { return pair.second->isFrequent(now); });
+ const auto& infos = history().mActiveLayerInfos;
+ return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) {
+ return pair.second.second->isFrequent(now);
+ });
}
auto animatingLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
- const auto& infos = history().mLayerInfos;
- return std::count_if(infos.begin(),
- infos.begin() + static_cast<long>(history().mActiveLayersEnd),
- [now](const auto& pair) { return pair.second->isAnimating(now); });
+ const auto& infos = history().mActiveLayerInfos;
+ return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) {
+ return pair.second.second->isAnimating(now);
+ });
}
void setDefaultLayerVote(Layer* layer,
LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS {
- for (auto& [layerUnsafe, info] : history().mLayerInfos) {
- if (layerUnsafe == layer) {
- info->setDefaultLayerVote(vote);
- return;
- }
+ auto [found, layerPair] = history().findLayer(layer->getSequence());
+ if (found != LayerHistory::layerStatus::NotFound) {
+ layerPair->second->setDefaultLayerVote(vote);
}
}
@@ -144,6 +153,8 @@
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+ // history().registerLayer(layer, LayerHistory::LayerVoteType::Max);
+
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -368,9 +379,9 @@
}
TEST_F(LayerHistoryTest, multipleLayers) {
- auto layer1 = createLayer();
- auto layer2 = createLayer();
- auto layer3 = createLayer();
+ auto layer1 = createLayer("A");
+ auto layer2 = createLayer("B");
+ auto layer3 = createLayer("C");
EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
@@ -654,6 +665,29 @@
EXPECT_EQ(1, animatingLayerCount(time));
}
+TEST_F(LayerHistoryTest, getFramerate) {
+ auto layer = createLayer();
+
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ nsecs_t time = systemTime();
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+
+ // layer is active but infrequent.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+ }
+
+ float expectedFramerate = 1e9f / MAX_FREQUENT_LAYER_PERIOD_NS.count();
+ EXPECT_FLOAT_EQ(expectedFramerate, history().getLayerFramerate(time, layer->getSequence()));
+}
+
TEST_F(LayerHistoryTest, heuristicLayer60Hz) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index dabd2d2..364d8f1 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -67,11 +67,16 @@
auto& mutableLayerHistory() { return mLayerHistory; }
- size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mLayerInfos.size(); }
- size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mActiveLayersEnd; }
+ size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS {
+ return mLayerHistory.mActiveLayerInfos.size() + mLayerHistory.mInactiveLayerInfos.size();
+ }
auto refreshRateConfigs() { return holdRefreshRateConfigs(); }
+ size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS {
+ return mLayerHistory.mActiveLayerInfos.size();
+ }
+
void replaceTouchTimer(int64_t millis) {
if (mTouchTimer) {
mTouchTimer.reset();
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index ffe5671..71c7bd9 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -165,7 +165,7 @@
mTracing->onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent",
123 /* flags */, -1 /* parentId */);
const sp<IBinder> fakeChildLayerHandle = new BBinder();
- mTracing->onLayerAdded(fakeChildLayerHandle->localBinder(), 2 /* layerId */, "child",
+ mTracing->onLayerAdded(fakeChildLayerHandle->localBinder(), mChildLayerId, "child",
456 /* flags */, mParentLayerId);
// add some layer transaction
@@ -179,7 +179,8 @@
transaction.states.add(layerState);
ComposerState childState;
childState.state.surface = fakeChildLayerHandle;
- layerState.state.z = 43;
+ childState.state.what = layer_state_t::eLayerChanged;
+ childState.state.z = 43;
transaction.states.add(childState);
mTracing->addQueuedTransaction(transaction);
@@ -227,6 +228,7 @@
}
int mParentLayerId = 1;
+ int mChildLayerId = 2;
int64_t mVsyncId = 0;
int64_t VSYNC_ID_FIRST_LAYER_CHANGE;
int64_t VSYNC_ID_SECOND_LAYER_CHANGE;
@@ -244,8 +246,11 @@
EXPECT_GT(proto.entry().size(), 0);
EXPECT_GT(proto.entry(0).transactions().size(), 0);
EXPECT_GT(proto.entry(0).added_layers().size(), 0);
- EXPECT_GT(proto.entry(0).transactions(0).layer_changes().size(), 0);
+ EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 2);
+ EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 42);
+ EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(1).layer_id(), mChildLayerId);
+ EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(1).z(), 43);
}
TEST_F(TransactionTracingLayerHandlingTest, updateStartingState) {
@@ -288,4 +293,69 @@
EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
}
+class TransactionTracingMirrorLayerTest : public TransactionTracingTest {
+protected:
+ void SetUp() override {
+ TransactionTracingTest::SetUp();
+ mTracing->enable();
+ // add layers
+ mTracing->setBufferSize(SMALL_BUFFER_SIZE);
+ const sp<IBinder> fakeLayerHandle = new BBinder();
+ mTracing->onLayerAdded(fakeLayerHandle->localBinder(), mLayerId, "Test Layer",
+ 123 /* flags */, -1 /* parentId */);
+ const sp<IBinder> fakeMirrorLayerHandle = new BBinder();
+ mTracing->onMirrorLayerAdded(fakeMirrorLayerHandle->localBinder(), mMirrorLayerId, "Mirror",
+ mLayerId);
+
+ // add some layer transaction
+ {
+ TransactionState transaction;
+ transaction.id = 50;
+ ComposerState layerState;
+ layerState.state.surface = fakeLayerHandle;
+ layerState.state.what = layer_state_t::eLayerChanged;
+ layerState.state.z = 42;
+ transaction.states.add(layerState);
+ ComposerState mirrorState;
+ mirrorState.state.surface = fakeMirrorLayerHandle;
+ mirrorState.state.what = layer_state_t::eLayerChanged;
+ mirrorState.state.z = 43;
+ transaction.states.add(mirrorState);
+ mTracing->addQueuedTransaction(transaction);
+
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back(transaction);
+ mTracing->addCommittedTransactions(transactions, ++mVsyncId);
+ flush(mVsyncId);
+ }
+ }
+
+ void TearDown() override {
+ mTracing->disable();
+ verifyDisabledTracingState();
+ TransactionTracingTest::TearDown();
+ }
+
+ int mLayerId = 5;
+ int mMirrorLayerId = 55;
+ int64_t mVsyncId = 0;
+ int64_t VSYNC_ID_FIRST_LAYER_CHANGE;
+ int64_t VSYNC_ID_SECOND_LAYER_CHANGE;
+ int64_t VSYNC_ID_CHILD_LAYER_REMOVED;
+};
+
+TEST_F(TransactionTracingMirrorLayerTest, canAddMirrorLayers) {
+ proto::TransactionTraceFile proto = writeToProto();
+ // We don't have any starting states since no layer was removed from.
+ EXPECT_EQ(proto.entry().size(), 2);
+ EXPECT_EQ(proto.entry(0).transactions().size(), 0);
+ EXPECT_EQ(proto.entry(0).added_layers().size(), 0);
+
+ // Verify the mirror layer was added
+ EXPECT_EQ(proto.entry(1).transactions().size(), 1);
+ EXPECT_EQ(proto.entry(1).added_layers().size(), 2);
+ EXPECT_EQ(proto.entry(1).added_layers(1).layer_id(), mMirrorLayerId);
+ EXPECT_EQ(proto.entry(1).transactions(0).layer_changes().size(), 2);
+ EXPECT_EQ(proto.entry(1).transactions(0).layer_changes(1).z(), 43);
+}
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 1ba3c0f..1debd65 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -136,7 +136,9 @@
const std::vector<uint8_t>&));
MOCK_METHOD1(getLayerGenericMetadataKeys,
V2_4::Error(std::vector<IComposerClient::LayerGenericMetadataKey>*));
- MOCK_METHOD2(getClientTargetProperty, Error(Display, IComposerClient::ClientTargetProperty*));
+ MOCK_METHOD3(getClientTargetProperty,
+ Error(Display, IComposerClient::ClientTargetProperty*, float*));
+ MOCK_METHOD3(setLayerWhitePointNits, Error(Display, Layer, float));
};
} // namespace Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index fe1544e..83a0996 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -85,7 +85,8 @@
MOCK_METHOD(hal::Error, getSupportedContentTypes, (std::vector<hal::ContentType> *),
(const, override));
MOCK_METHOD(hal::Error, setContentType, (hal::ContentType), (override));
- MOCK_METHOD(hal::Error, getClientTargetProperty, (hal::ClientTargetProperty *), (override));
+ MOCK_METHOD(hal::Error, getClientTargetProperty, (hal::ClientTargetProperty *, float *),
+ (override));
};
class Layer : public HWC2::Layer {
@@ -116,6 +117,7 @@
MOCK_METHOD(hal::Error, setColorTransform, (const android::mat4 &), (override));
MOCK_METHOD(hal::Error, setLayerGenericMetadata,
(const std::string &, bool, const std::vector<uint8_t> &), (override));
+ MOCK_METHOD(hal::Error, setWhitePointNits, (float whitePointNits), (override));
};
} // namespace android::HWC2::mock
diff --git a/vulkan/libvulkan/debug_report.h b/vulkan/libvulkan/debug_report.h
index e5b1587..416c0bc 100644
--- a/vulkan/libvulkan/debug_report.h
+++ b/vulkan/libvulkan/debug_report.h
@@ -78,8 +78,7 @@
VkDebugReportCallbackEXT driver_handle;
};
- // TODO(b/143295577): use std::shared_mutex when available in libc++
- mutable std::shared_timed_mutex rwmutex_;
+ mutable std::shared_mutex rwmutex_;
Node head_;
};